package controllers;

import play.*;
import play.cache.Cache;
import play.data.binding.As;
import play.data.validation.Email;
import play.data.validation.Required;
import play.data.validation.Validation;
import play.data.validation.Validation.ValidationResult;
import play.db.jpa.GenericModel;
import play.libs.Mail;
import play.modules.search.Query;
import play.modules.search.Search;
import play.mvc.*;
import play.test.Fixtures;
import java.io.IOError;
import java.io.IOException;
import java.security.Permission;
import java.util.*;

import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
import org.hibernate.annotations.ParamDef;
import org.hibernate.mapping.Array;

import models.*;

@With(Secure.class)
public class Application extends Controller {

	public static void index() {
		if (Security.isConnected()) {

			if(!session.get("username").equalsIgnoreCase("guest")){
			Users.showWall();
		}
		else{
			List<Organization> randomOrgs = new ArrayList<Organization>();
			randomOrgs = Organization.find("privacyStatus", 0).fetch();
			List<Organization> orgs = new ArrayList<Organization>();
			for(int i = 0; (i<3 && i <randomOrgs.size()); i++){
				if(randomOrgs.get(i)!=null){
					orgs.add(randomOrgs.get(i));

							}
				}
				render(orgs);
			}
		}

	}

	/**
	 * Method to show the plan(requirements and update status) through the
	 * planStuff.html
	 * 
	 * @author Islam Al-Aarag
	 * @param planId
	 *            the id of the plan to be rendered(viewed)
	 */
	public static void planStuff(long planId) {
		Plan plan = Plan.findById(planId);
		double status = plan.status;
		if (plan != null) {
			render(plan);
			render(status);
			render(plan.requirements);
		} else
			notExistingPlan();
	}

	/**
	 * show the main page of plan containing all its information and customized
	 * according to the showing user
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param planId
	 *            the id of the plan to be rendered(viewed)
	 * @see app/views/Application/showPlan.html
	 */
	public static void showPlan(long planId) {
		Plan plan = Plan.findById(planId);
		if (plan != null) {
			plan.numberOfView++;
			if (plan.ideasToBeRemoved != null) {
				plan.ideasToBeRemoved.clear();
				plan.save();
			}
			if (plan.toBeRemoved != null) {
				plan.toBeRemoved.clear();
				plan.save();
			}
			render(plan);
		} else {
			notExistingPlan();
		}
	}

	public static void progressBar(long planId) {
		Plan plan = Plan.findById(planId);
		if (plan == null)
			notExistingPlan();
		else
			render(plan);
	}

	public static void theProgressBar(long planId) {
		Plan plan = Plan.findById(planId);
		if (plan == null)
			notExistingPlan();
		else
			render(plan);
	}

	/**
	 * @author Omar Fouda method to get the type of user logged in
	 * @return array list of the types that this user is organizer of an entity
	 *         =1, organization lead = 2
	 */
	/*
	 * public static List<Integer> getType() { List<Integer> type = new
	 * ArrayList<Integer>(); List<EEntity> myEntities = isHeAnOrganizer();
	 * 
	 * if (myEntities != null) { if (myEntities.size() > 0) {
	 * 
	 * type.add(1); } } List<Organization> myOrgs = isHeAnOrganizationLead();
	 * 
	 * if (myOrgs != null) { if (myOrgs.size() > 0) {
	 * System.out.println("adsa"); type.add(2); } } return type; }
	 */
	/**
	 * @author Omar Fouda method to return list of organizations, a user is a
	 *         lead in
	 * @return list of organizations
	 */
	/*
	 * public static List<Organization> isHeAnOrganizationLead() {
	 * List<Organization> result = null;
	 * 
	 * if (Security.isConnected()) {
	 * 
	 * String userName = session.get("username"); User user =
	 * User.find("userName", userName).first();
	 * 
	 * if (user != null) {
	 * 
	 * result = new ArrayList<Organization>(); List<RoleInOrganization> list =
	 * RoleInOrganization.findAll(); List<Organization> organization =
	 * Organization.findAll(); for (RoleInOrganization record : list) { for
	 * (Organization record2 : organization) { if (record.organization.id ==
	 * record2.id && record.user.id == user.id && record.role.description
	 * .equalsIgnoreCase("organizationLead")) {
	 * 
	 * result.add(record2); } } } } } return result; }
	 */
	/**
	 * @author Omar Fouda method to return list of entities, a user is an
	 *         organizer in
	 * @return list of entities
	 */

	/*
	 * public static List<EEntity> isHeAnOrganizer() {
	 * 
	 * List<EEntity> result = null; if (Security.isConnected()) {
	 * 
	 * String userName = session.get("username"); User user =
	 * User.find("userName", userName).first();
	 * 
	 * if (user != null) { result = new ArrayList<EEntity>(); List<RoleInEntity>
	 * list = RoleInEntity.findAll(); List<EEntity> entity = EEntity.findAll();
	 * for (RoleInEntity record : list) { for (EEntity record2 : entity) { if
	 * (record.entity.id == record2.id && record.user.id == user.id &&
	 * record.role.description .equalsIgnoreCase("Organizer")) {
	 * result.add(record2); } } } } } return result; }
	 */
	/**
	 * adds newly created action item to the to-do-list of a plan after
	 * validating the user input as arguments to the constructor of the action
	 * item
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param planId
	 *            the id of the plan whose to-do-list will be updated with the
	 *            new action item
	 * 
	 * @param itemDescription
	 *            the description of the new action item
	 * @param stDate
	 *            the string representing start date of execution of the action
	 *            item
	 * @param endDate
	 *            the string representing date of finishing the work on this
	 *            action item
	 * 
	 * @param topicId
	 *            Id of the topic the action item should be related to
	 *            Optional!, if not set, set to null
	 * 
	 * @param entityId
	 *            Id of entity the item has to be related to Optional!, if not
	 *            set, set to null
	 * 
	 * 
	 * @see app/views/Application/showPlan.html
	 */
	public static void addActionItem(long planId, long topicId, long entityId,
			String itemDescription, String stDate, String endDate) {
		Plan plan = Plan.findById(planId);
		Topic topic = Topic.findById(topicId);
		Topic entity = Topic.findById(entityId);
		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("byUserName", userName).first();
			if (user == null
					|| (user.id != plan.creator.id && !user.isSysteAdmin())) {
				notAuthorized();
			}
		} else {
			notAuthorized();
		}
		boolean correctStartDate = false, correctEndDate = false;
		Date start = null, end = null;
		validation.required(itemDescription).message(
				"You must enter Item Description");
		validation.minSize(itemDescription, 10).message(
				"The description can not be less than 10 letters");
		if (stDate.length() > 0) {
			ValidationResult vr = validation
					.match(stDate,
							"^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
			vr.message("The start date fomate is not correct make it like yyyy-mm-dd and you better choose from the calender !!!");
			if (vr.ok == true) {
				correctStartDate = true;
				String[] t = stDate.split("-");
				start = parseDate(t[2] + "-" + t[1] + "-" + t[0]);
			}
		}
		if (endDate.length() > 0) {
			ValidationResult vr = validation
					.match(endDate,
							"^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
			vr.message("The end date fomate is not correct make it like yyyy-mm-dd and you better choose from the calender !!!");
			if (vr.ok == true) {
				correctEndDate = true;
				String[] t = endDate.split("-");
				end = parseDate(t[2] + "-" + t[1] + "-" + t[0]);
			}
		}
		Date date = new Date();
		if (correctStartDate && start != null && date.compareTo(start) > 0) {
			validation.addError(stDate, "The start date is in the past",
					endDate);
			validation.keep();
		}
		if (correctEndDate && correctStartDate && start != null && end != null
				&& start.compareTo(end) > 0) {
			validation.addError(stDate,
					"The end date is before the start date", endDate);
			validation.keep();
		}
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			showPlan(planId);
		} else {
			ActionItem item = new ActionItem(itemDescription, start, end)
					.save();
			long itemId = item.getId();
			plan.addActionItem(item.getId());
			plan.save();
			if (topic != null) {
				topic.addActionItem(itemId);
				topic.save();
			}
			if (entity != null) {
				entity.addActionItem(itemId);
				entity.save();
			}
			User user = User.find("byUserName", userName).first();
			String blockedUserIdMsg = "User name " + user.name
					+ " added Action Item to Plan " + plan.title;
			new ActionLog(blockedUserIdMsg, user, null).save();
			showPlan(planId);
		}
	}

	/*
	 * Shows the add action item dialogue
	 * 
	 * @author Jonas Wilhelm
	 */

	public static void showAddActionItem() {
		render();
	}

	/**
	 * Method which evaluates the given ID and shows the according action items
	 * 
	 * @author Jonas Wilhelm
	 * 
	 * @param ID
	 *            User, EEntity, Topic or Plan ID
	 * 
	 * @param type
	 *            Type of ID in order to detmerine which items to be displayed
	 */

	public static void showActionItems(long ID, String type) {
		List<ActionItem> actionItems = new ArrayList<ActionItem>();

		if (type.equalsIgnoreCase("user")) {
			User user = User.findById(ID);
			if (user != null) {
				actionItems = user.actionItems;
			}
		} else if (type.toLowerCase() == "entity") {
			EEntity entity = EEntity.findById(ID);
			if (entity != null) {
				actionItems = entity.items;
			}
		} else if (type.toLowerCase() == "topic") {
			Topic topic = Topic.findById(ID);
			if (topic != null) {
				actionItems = topic.items;
			}
		} else if (type.equals("plan")) {
			Plan plan = Plan.findById(ID);
			if (plan != null) {
				actionItems = plan.actionItems;
			}
		}

		render(actionItems);
	}

	/**
	 * @author Jonas Wilhelm
	 * 
	 *         Method is used to view the action item form for editing
	 * 
	 * @param itemID
	 *            ID of the item to be shown
	 * 
	 * @param action
	 *            Contains the action to be done. Either 'add' or 'edit'
	 * 
	 **/

	public static void showEditActionItem(long itemId) {
		ActionItem item = ActionItem.findById(itemId);
		if (item == null)
			notExistingActionItem();
		render(item);
	}

	/**
	 * Used to edit an action item, that the attributes of the action item are
	 * changed to the new values passed to this method
	 * 
	 * @param itemId
	 *            The ID of the action item to be edited
	 * @param newDescription
	 *            The new description of the action item
	 * @param newStartDate
	 *            The new start date of the action item
	 * @param newEndDate
	 *            The new end date of the action item
	 * @author Sherif Ayad
	 */
	public static void editActionItem(long itemId, String newDescription,
			String newStartDate, String newEndDate) {
		ActionItem item = ActionItem.findById(itemId);
		if (item == null)
			notExistingActionItem();
		else {
			boolean correctStartDate = false, correctEndDate = false;
			Date start = null, end = null;
			validation.required(newDescription).message(
					"You must enter item Description");
			validation.required(newStartDate).message(
					"You must enter a start date for the action item");
			validation.required(newEndDate).message(
					"You must enter an end date for the action item");
			validation.minSize(newDescription, 10).message(
					"The item description can not be less than 10 letters");
			if (newStartDate.length() > 0) {
				ValidationResult vr = validation
						.match(newStartDate,
								"^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
				vr.message("The start date format is not correct make it like yyyy-mm-dd and you better choose from the calender !!!");
				if (vr.ok == true) {
					correctStartDate = true;
					String[] splitted = newStartDate.split("-");
					start = parseDate(splitted[2] + "-" + splitted[1] + "-"
							+ splitted[0]);
				}
			}
			if (newEndDate.length() > 0) {
				ValidationResult vr = validation
						.match(newEndDate,
								"^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
				vr.message("The end date format is not correct make it like yyyy-mm-dd and you better choose from the calender !!!");
				if (vr.ok == true) {
					correctEndDate = true;
					String[] splitted = newEndDate.split("-");
					end = parseDate(splitted[2] + "-" + splitted[1] + "-"
							+ splitted[0]);
				}
			}
			Date date = new Date();
			if (correctStartDate && start != null && date.compareTo(start) > 0) {
				validation.addError(newStartDate,
						"The start date is in the past", newEndDate);
				validation.keep();
			}
			if (correctEndDate && correctStartDate && start != null
					&& end != null && start.compareTo(end) > 0) {
				validation.addError(newStartDate,
						"The end date is before the start date", newEndDate);
				validation.keep();
			}
			if (validation.hasErrors()) {
				params.flash();
				validation.keep();
				showEditActionItem(item.id);
			} else {
				item.description = newDescription;
				String[] splitted = newStartDate.split("-");
				item.startDate = parseDate(splitted[2] + "-" + splitted[1]
						+ "-" + splitted[0]);
				splitted = newEndDate.split("-");
				item.endDate = parseDate(splitted[2] + "-" + splitted[1] + "-"
						+ splitted[0]);
				item.save();
				showPlan(item.plan.id);
			}
		}
	}

	/**
	 * @author Mostafa M. Ayman
	 * 
	 *         send a request to participate in an ActionItem to the
	 *         creator/organizer of the plan.
	 * @param request
	 *            The request or the reason. The user needs to fill this in
	 *            order to participate in an action plan, Better yet, he can not
	 *            send the e-mail unless the he fills the request.
	 * 
	 * @param planId
	 *            the Plan ID.
	 * 
	 * @story C570
	 * 
	 **/
	public static void sendActionItemJoinRequest(String request, long planId,
			long itemId) {
		System.out.println(request + " " + planId + " " + itemId);
		Plan plan = Plan.findById(planId);
		if (plan == null) {
			validation
					.error("you're trying to reach a non-existent plan, please choos a plan or else go ponder in other universes looking for a plan.");
		}
		validation.required(request);
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			showPlan(plan.id);
		}
		Date invitationDate = new Date();
		ActionItem item = ActionItem.findById(itemId);
		User recievingUser = item.plan.creator;
		// Organization current =
		// item.plan.ideas.get(0).topic.entity.organization;
		Organization current = Organization.findById(1L);
		String description = session.get("username")
				+ " requested to join that action item";
		Request aRequest = new Request((User) User.find("byUserName",
				session.get("username")).first(), current, recievingUser,
				invitationDate, description).save();
		item.requestsToJoin.add(aRequest);
		item.save();
		String sent = "S E N T successfully";
		String failed = "failure";
		boolean send = sendMail(
				request,
				"request to participate in an action item from user "
						+ session.get("username"), plan.creator.getEmail(),
				session.get("username"));
		if (send) {
			renderText(sent);
			sendMail("balala", "aywa", plan.creator.getEmail(),
					session.get("username"));
		} else
			renderText(failed);
	}

	/*
	 * // Just for takeInfo public static boolean sendEMail(String sender,
	 * String reciever, String theMail){ return true; }
	 */

	/**
	 * 
	 * 
	 * 
	 * 
	 * @author Mostafa M. Ayman
	 * 
	 * @param planId
	 *            the ID of the plan
	 * @param progress
	 *            the string that the user will insert as a progress in the
	 *            plan.
	 * 
	 *            this method will update the status of a plan.
	 * 
	 * @story C5S68
	 * 
	 *        * @story
	 * 
	 * 
	 */

	public static void updateStatus(long planId, String progress) {

		Plan plan = Plan.findById(planId);
		// ArrayList <Double> statusData = new ArrayList<Double>();
		if (plan == null) {
			notExistingPlan();
		}
		ValidationResult vr = validation.match(progress,
				"^([-]?)([0-9]+)((.[0-9]{2})?)$");
		vr.message("Please enter only double values!!!");
		if (vr.ok == true) {
			double prog = Double.parseDouble(progress);
			if (prog < 0 || prog > 100)
				validation
						.addError("",
								"Please enter a number between 0.1% and 100%",
								progress);
			// pleaseChoose();
		}
		double theStatus;
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			renderText("faliure");
		}
		String userName = session.get("username");
		theStatus = Double.parseDouble(progress);
		plan.status = theStatus;
		// statusData.add(theStatus);
		plan.save();
		String statusUpdate = "User" + session.get("username")
				+ "Updated Status To" + theStatus + "to the following Plan:"
				+ plan.id;
		// new ActionLog(statusUpdate, , null).save();
		renderText("success");
	}

	public static void calculateTheProgress(double old_status, double new_status) {

	}

	/**
	 * 
	 * add request to a certain plan which is associated with the planId which
	 * is also a parameter in this method, then add them to the Array List of
	 * requirements of the plan.
	 * 
	 * 
	 * @author Mostafa M. Ayman
	 * 
	 * @param planId
	 *            the ID of the plan
	 * @param req
	 *            the string that the user will insert as a requirement.
	 * 
	 * 
	 * 
	 */
	public static void addReqs(long planId, String req) {
		Plan plan = Plan.findById(planId);
		if (plan == null) {
			notExistingPlan();
		}
		validation.required(req).message("You must enter a requirement");
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			showPlan(planId);
		}
		plan.requirements.add(req);
		plan.save();
		showPlan(planId);
	}

	/**
	 * method to remove requirement from a certain plan.
	 * 
	 * @param reqNo
	 *            requirement number
	 * @author Mostafa M. Ayman
	 * 
	 * @story C5S70
	 */
	public static void removeRequirement(long planId, int reqNo) {
		Plan plan = Plan.findById(planId);
		boolean flagAlmostEmpty = false;
		boolean flagA = false;
		boolean flagAlmostAlmostEmpty = false;

		for (int i = 0; i <= plan.requirements.size(); i++) {
			String number = Integer.toString(i);
			// plan.virtualRequirements.add(i, number);
		}

		if (reqNo == plan.requirements.size()) {
			plan.requirements.remove(reqNo - 1);
		} else {
			if (plan.requirements.size() != 1) {
				plan.requirements.remove(reqNo - 1);

			} else {
				plan.requirements.remove(reqNo);

			}
		}
		plan.save();
		showPlan(planId);
	}

	/**
	 * clean/clear all the requirements in the plan
	 * 
	 * @param planId
	 *            Plan ID
	 * @author Mostafa M. Ayman
	 * 
	 * @story C5S70
	 */
	public static void cleanRequirements(long planId) {
		Plan plan = Plan.findById(planId);
		if (plan == null) {
			validation.error("The plan you choose does not exist");
			showPlan(planId);
		}

		plan.requirements.clear();
		plan.save();
		showPlan(planId);
	}

	/**
	 * The method searches for ideas that were posted a week ago and then check
	 * for their comments if there were no new comments for a week.
	 * 
	 * @return ArrayList, List of Ideas that were inactive for 1 week.
	 * @author Ahmed Mahmoud
	 */
	public static ArrayList<Idea> getInactiveIdeas() {
		ArrayList<Idea> inactiveIdeas = new ArrayList<Idea>();
		List<Idea> ideas = Idea.findAll();
		for (Idea idea : ideas) {
			if (!idea.isActive()) {
				inactiveIdeas.add(idea);
			}
		}

		return inactiveIdeas;
	}

	/**
	 * The method searches for Topics that were posted a week ago and then check
	 * for their ideas & the comments on the ideas if there were no new ideas or
	 * comments for a week.
	 * 
	 * @return ArrayList, List of Topics that were inactive for 1 week.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static ArrayList<Topic> getInactiveTopics() {
		// the value 514800000 is 7 or 6 day difference.
		ArrayList<Topic> inactiveTopics = new ArrayList<Topic>(10);
		List<Topic> topics = Topic.findAll();
		for (Topic topic : topics) {
			if (!topic.isActive() && topic.status != 1) {
				topic.status = 1; // setting the status of the topic to be
									// inactive
				inactiveTopics.add(topic);
			}
		}

		return inactiveTopics;
	}

	/**
	 * checks if given date in milliseconds is within a week of the date of the
	 * check.
	 * 
	 * @param date
	 *            a date representation in milliseconds
	 * @return boolean, true if the date is within a week. false if it's older
	 *         than a week.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static boolean isNewDate(Long date) {
		// the value 514800000 is 7 or 6 day difference.
		if (System.currentTimeMillis() - date < 514800000) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * the method takes a a user and msg and subject and send the mail to those
	 * users.
	 * 
	 * @param msg
	 *            the body of the Mail.
	 * @param subject
	 *            the subject of the Mail.
	 * @param to
	 *            the Users to whom u'll send the message.
	 * @return boolean, true if the msg was sent. False otherwise.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static boolean sendMail(String msg, String subject, User... to) {
		boolean isSent = true;
		for (int i = 0; i < to.length; i++) {
			isSent &= sendMail(msg, subject, to[i].email, to[i].name);
		}
		return isSent;
	}

	/**
	 * the method takes a a user and msg and subject and send the mail to those
	 * users.
	 * 
	 * @param msg
	 *            the body of the Mail.
	 * @param subject
	 *            the subject of the Mail.
	 * @param to
	 *            the Users to whom u'll send the message.
	 * @return boolean, true if the msg was sent to all the users. False
	 *         otherwise.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static boolean sendMail(String msg, String subject, List<User> to) {
		boolean isSent = true;
		for (User user : to) {
			isSent &= sendMail(msg, subject, user.email, user.name);
		}
		return isSent;
	}

	/**
	 * 
	 * @param msg
	 *            the body of the mail
	 * @param subject
	 *            the subject of the mail
	 * @param toEmail
	 *            the email address to whom te mail will be sent.
	 * @param name
	 *            name of the email address owener. ( if sent null or empty
	 *            string it'll be ignored).
	 * @return boolean, true if the mail was sent. false otherwise.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static boolean sendMail(String msg, String subject, String toEmail,
			String name) {
		try {
			SimpleEmail email = new SimpleEmail();
			email.setFrom("supersoft.notification@gmail.com",
					"Notificain Sender");
			if (name == null || name.equals("")) {
				name = toEmail;
			}
			email.addTo(toEmail, name);
			email.setSubject(subject);
			email.setMsg(msg);
			Mail.send(email);
		} catch (EmailException e) {

			e.printStackTrace();
			return false;
		} catch (Exception e) {

			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * this method gets list of all search results like ideas,topics,... related
	 * to a certain keyword
	 * 
	 * @author amr ahmed
	 * 
	 * @category c4s50
	 * 
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * @return List<Object>
	 */
	public static List getResults(String searchKeyWord) {
		searchKeyWord = searchKeyWord.toLowerCase();
		List<Object> allResults = new LinkedList();
		// Ideas
		Query qIdea = (Query) Search.search("title:" + searchKeyWord,
				Idea.class);
		List<Idea> ideaByTitleResult = qIdea.fetch();

		List<Idea> ideaByTagResult = Idea.searchByTag(searchKeyWord);
		allResults.add(ideaByTitleResult);
		allResults.add(ideaByTagResult);

		// Organization
		Query qOrg = (Query) Search.search("name:" + searchKeyWord,
				Organization.class);
		List<Organization> orgByNameResult = qOrg.fetch();
		allResults.add(orgByNameResult);

		// Entity
		Query qEntity = (Query) Search.search("name:" + searchKeyWord,
				EEntity.class);
		List<EEntity> entityByNameResult = qEntity.fetch();
		List<EEntity> entityByKeyResult = EEntity
				.searchByKeyword(searchKeyWord);
		allResults.add(entityByNameResult);
		allResults.add(entityByKeyResult);

		// plan
		Query qPlan = (Query) Search.search("title:" + searchKeyWord,
				Plan.class);
		List<Plan> planByTitleResult = qPlan.fetch();
		allResults.add(planByTitleResult);

		// topic
		Query qTopic = (Query) Search.search("name:" + searchKeyWord,
				Topic.class);
		List<Topic> topicByNameResult = qTopic.fetch();
		List<Topic> topicByTagResult = Topic.searchByTag(searchKeyWord);
		allResults.add(topicByNameResult);
		allResults.add(topicByTagResult);

		long id = -1;
		String userName = session.get("username");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			if (user != null) {
				id = user.id;
			}
		}
		LinkedList<Object> hashObj = new LinkedList<Object>();
		hashObj.add(id);
		hashObj.add(searchKeyWord);
		String key = hashObj.hashCode() + "";
		play.cache.Cache.safeSet(key, allResults, "30mn");

		return (allResults);

	}

	/**
	 * this method gets list of all search results from getResults() and get
	 * each type of results as a list then it renders all the lists
	 * 
	 * @author amr ahmed
	 * @category C4S50
	 * 
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * 
	 */
	public static void searchResults(String searchKeyWord) {

		validation.required(searchKeyWord).message("Empty Field");
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			index();
		} else {
			long id;
			String userName = session.get("userName");
			User user = null;
			if (userName != null) {
				user = User.find("byUserName", userName).first();
				id = user.id;
			} else {
				id = -1;
			}

			List results = getResults(searchKeyWord);
			List<Idea> ideaByTitleResult = (List<Idea>) results.get(0);
			List<Idea> ideaByTagResult = (List<Idea>) results.get(1);
			List<Organization> orgByNameResult = (List<Organization>) results
					.get(2);
			List<EEntity> entityByNameResult = (List<EEntity>) results.get(3);
			List<EEntity> entityByKeyResult = (List<EEntity>) results.get(4);
			List<Plan> planByTitleResult = (List<Plan>) results.get(5);
			List<Topic> topicByNameResult = (List<Topic>) results.get(6);
			List<Topic> topicByTagResult = (List<Topic>) results.get(7);

			render(id, searchKeyWord, ideaByTitleResult, ideaByTagResult,
					orgByNameResult, entityByNameResult, entityByKeyResult,
					planByTitleResult, topicByNameResult, topicByTagResult);
		}
	}

	/**
	 * this method gets list of all search results from getResults() and get
	 * each type of results as a list then sorts all the lists desc according to
	 * the number of views then it renders all the lists
	 * 
	 * @author amr ahmed
	 * @category C4S65
	 * 
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * 
	 */
	public static void sortByViews(String searchKeyWord) {

		long id;
		String userName = session.get("userName");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			id = user.id;
		} else {
			id = -1;
		}

		List results = getResults(searchKeyWord);
		List<Idea> ideaByTitleResult = (List<Idea>) results.get(0);
		OrderIdeaByViews.sort((ArrayList<Idea>) ideaByTitleResult);
		List<Idea> ideaByTagResult = (List<Idea>) results.get(1);
		OrderIdeaByViews.sort((ArrayList<Idea>) ideaByTagResult);
		Collections.reverse(ideaByTagResult);
		Collections.reverse(ideaByTitleResult);

		List<Organization> orgByNameResult = (List<Organization>) results
				.get(2);
		OrderOrgByViews.sort((ArrayList<Organization>) orgByNameResult);
		Collections.reverse(orgByNameResult);

		List<EEntity> entityByNameResult = (List<EEntity>) results.get(3);
		OrderEntityByViews.sort((ArrayList<EEntity>) entityByNameResult);
		List<EEntity> entityByKeyResult = (List<EEntity>) results.get(4);
		OrderEntityByViews.sort((ArrayList<EEntity>) entityByKeyResult);
		Collections.reverse(entityByNameResult);
		Collections.reverse(entityByKeyResult);

		List<Plan> planByTitleResult = (List<Plan>) results.get(5);
		OrderPlanByViews.sort((ArrayList<Plan>) planByTitleResult);
		Collections.reverse(planByTitleResult);

		List<Topic> topicByNameResult = (List<Topic>) results.get(6);
		OrderTopicByViews.sort((ArrayList<Topic>) topicByNameResult);
		List<Topic> topicByTagResult = (List<Topic>) results.get(7);
		OrderTopicByViews.sort((ArrayList<Topic>) topicByTagResult);
		Collections.reverse(topicByNameResult);
		Collections.reverse(topicByTagResult);

		render(id, searchKeyWord, ideaByTitleResult, ideaByTagResult,
				orgByNameResult, entityByNameResult, entityByKeyResult,
				planByTitleResult, topicByNameResult, topicByTagResult);
	}

	/**
	 * this method gets list of all search results from getResults() and get
	 * each type of results as a list then sorts all the lists desc according to
	 * the rating then it renders all the lists
	 * 
	 * @author amr ahmed
	 * @category C4S65
	 * 
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * 
	 */
	public static void sortByRating(String searchKeyWord) {

		long id;
		String userName = session.get("userName");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			id = user.id;
		} else {
			id = -1;
		}

		List results = getResults(searchKeyWord);
		List<Idea> ideaByTitleResult = (List<Idea>) results.get(0);
		OrderIdeaByRating.sort((ArrayList<Idea>) ideaByTitleResult);
		List<Idea> ideaByTagResult = (List<Idea>) results.get(1);
		OrderIdeaByRating.sort((ArrayList<Idea>) ideaByTagResult);
		Collections.reverse(ideaByTagResult);
		Collections.reverse(ideaByTitleResult);

		List<Organization> orgByNameResult = (List<Organization>) results
				.get(2);

		List<EEntity> entityByNameResult = (List<EEntity>) results.get(3);
		List<EEntity> entityByKeyResult = (List<EEntity>) results.get(4);

		List<Plan> planByTitleResult = (List<Plan>) results.get(5);
		OrderPlanByRating.sort((ArrayList<Plan>) planByTitleResult);
		Collections.reverse(planByTitleResult);

		List<Topic> topicByNameResult = (List<Topic>) results.get(6);
		OrderTopicByRating.sort((ArrayList<Topic>) topicByNameResult);
		List<Topic> topicByTagResult = (List<Topic>) results.get(7);
		OrderTopicByRating.sort((ArrayList<Topic>) topicByTagResult);
		Collections.reverse(topicByNameResult);
		Collections.reverse(topicByTagResult);

		render(id, searchKeyWord, ideaByTitleResult, ideaByTagResult,
				orgByNameResult, entityByNameResult, entityByKeyResult,
				planByTitleResult, topicByNameResult, topicByTagResult);
	}

	/**
	 * this method gets list of all search results from getResults() and get
	 * each type of results as a list then sorts all the lists asc according to
	 * the number of views then it renders all the lists
	 * 
	 * @author amr ahmed
	 * @category C4S65
	 * 
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * 
	 */
	public static void sortByViewsAsc(String searchKeyWord) {

		long id;
		String userName = session.get("userName");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			id = user.id;
		} else {
			id = -1;
		}

		List results = getResults(searchKeyWord);
		List<Idea> ideaByTitleResult = (List<Idea>) results.get(0);
		OrderIdeaByViews.sort((ArrayList<Idea>) ideaByTitleResult);
		List<Idea> ideaByTagResult = (List<Idea>) results.get(1);
		OrderIdeaByViews.sort((ArrayList<Idea>) ideaByTagResult);

		List<Organization> orgByNameResult = (List<Organization>) results
				.get(2);
		OrderOrgByViews.sort((ArrayList<Organization>) orgByNameResult);

		List<EEntity> entityByNameResult = (List<EEntity>) results.get(3);
		OrderEntityByViews.sort((ArrayList<EEntity>) entityByNameResult);
		List<EEntity> entityByKeyResult = (List<EEntity>) results.get(4);
		OrderEntityByViews.sort((ArrayList<EEntity>) entityByKeyResult);

		List<Plan> planByTitleResult = (List<Plan>) results.get(5);
		OrderPlanByViews.sort((ArrayList<Plan>) planByTitleResult);

		List<Topic> topicByNameResult = (List<Topic>) results.get(6);
		OrderTopicByViews.sort((ArrayList<Topic>) topicByNameResult);
		List<Topic> topicByTagResult = (List<Topic>) results.get(7);
		OrderTopicByViews.sort((ArrayList<Topic>) topicByTagResult);

		render(id, searchKeyWord, ideaByTitleResult, ideaByTagResult,
				orgByNameResult, entityByNameResult, entityByKeyResult,
				planByTitleResult, topicByNameResult, topicByTagResult);
	}

	/**
	 * this method gets list of all search results from getResults() and get
	 * each type of results as a list then sorts all the lists asc according to
	 * the rating then it renders all the lists
	 * 
	 * @author amr ahmed
	 * @category C4S65
	 * 
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * 
	 */
	public static void sortByRatingAsc(String searchKeyWord) {

		long id;
		String userName = session.get("userName");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			id = user.id;
		} else {
			id = -1;
		}

		List results = getResults(searchKeyWord);
		List<Idea> ideaByTitleResult = (List<Idea>) results.get(0);
		OrderIdeaByRating.sort((ArrayList<Idea>) ideaByTitleResult);
		List<Idea> ideaByTagResult = (List<Idea>) results.get(1);
		OrderIdeaByRating.sort((ArrayList<Idea>) ideaByTagResult);

		List<Organization> orgByNameResult = (List<Organization>) results
				.get(2);

		List<EEntity> entityByNameResult = (List<EEntity>) results.get(3);
		List<EEntity> entityByKeyResult = (List<EEntity>) results.get(4);

		List<Plan> planByTitleResult = (List<Plan>) results.get(5);
		OrderPlanByRating.sort((ArrayList<Plan>) planByTitleResult);

		List<Topic> topicByNameResult = (List<Topic>) results.get(6);
		OrderTopicByRating.sort((ArrayList<Topic>) topicByNameResult);
		List<Topic> topicByTagResult = (List<Topic>) results.get(7);
		OrderTopicByRating.sort((ArrayList<Topic>) topicByTagResult);

		render(id, searchKeyWord, ideaByTitleResult, ideaByTagResult,
				orgByNameResult, entityByNameResult, entityByKeyResult,
				planByTitleResult, topicByNameResult, topicByTagResult);
	}

	/**
	 * this gets the content of a comment on a certain idea then saves it and
	 * calls viewIdea()
	 * 
	 * @author amr ahmed
	 * @category C4S57
	 * @param content
	 *            the content of the comment
	 * @param ideaID
	 *            the id of the idea that was commented on
	 * 
	 */
	public static void saveComment(long ideaID, String content) {

		validation.required(content).message("Empty Field");
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			Browse.viewIdea(ideaID);
		} else {
			Idea idea = Idea.find("byID", ideaID).first();
			String userName = session.get("username");
			User user = null;
			if (userName != null) {

				user = User.find("byUserName", userName).first();
				if (idea != null
						&& idea.topic.entity.organization.isMember(user.id)
						&& !idea.isPromoted) {
					if (idea.comments.size() != 0) {
						if (idea.comments.get(idea.comments.size() - 1).content
								.compareTo(content) != 0) {
							Comment comment = new Comment(0, content, user,
									idea, null);
							comment.save();
							idea.comments.add(comment);
							idea.save();
							LinkedList<User> toBeNotified = new LinkedList<User>();
							for (User notifiedUser : idea.topic.followingUsers) {
								if (!toBeNotified.contains(notifiedUser))
									toBeNotified.add(notifiedUser);
							}
							for (User notifiedUser : idea.topic.entity.followingUsers) {
								if (!toBeNotified.contains(notifiedUser))
									toBeNotified.add(notifiedUser);
							}
							for (User notifiedUser : idea.topic.entity.organization.followingUsers) {
								if (!toBeNotified.contains(notifiedUser))
									toBeNotified.add(notifiedUser);
							}
							for (User notifiedUser : idea.subscribers) {
								if (!toBeNotified.contains(notifiedUser))
									toBeNotified.add(notifiedUser);
							}
							models.Notification newnot = new models.Notification(
									"A new comment has been added to idea "
											+ idea.title, comment.id, 2, user,
									toBeNotified);
							newnot.timeStamp = new Date();
							newnot.save();
							Browse.viewIdea(ideaID);
						} else {
							Browse.viewIdea(ideaID);
						}
					} else {
						Comment comment = new Comment(0, content, user, idea,
								null);
						comment.save();
						idea.comments.add(comment);
						idea.save();
						LinkedList<User> toBeNotified = new LinkedList<User>();
						for (User notifiedUser : idea.topic.followingUsers) {
							if (!toBeNotified.contains(notifiedUser))
								toBeNotified.add(notifiedUser);
						}
						for (User notifiedUser : idea.topic.entity.followingUsers) {
							if (!toBeNotified.contains(notifiedUser))
								toBeNotified.add(notifiedUser);
						}
						for (User notifiedUser : idea.topic.entity.organization.followingUsers) {
							if (!toBeNotified.contains(notifiedUser))
								toBeNotified.add(notifiedUser);
						}
						for (User notifiedUser : idea.subscribers) {
							if (!toBeNotified.contains(notifiedUser))
								toBeNotified.add(notifiedUser);
						}
						models.Notification newnot = new models.Notification(
								"A new comment has been added to idea "
										+ idea.title, comment.id, 2, user,
								toBeNotified);
						newnot.timeStamp = new Date();
						newnot.save();
						Browse.viewIdea(ideaID);
					}
				}
			}
		}
	}

	/**
	 * this gets the content of a comment on a certain plan then saves it and
	 * calls showPlan()
	 * 
	 * @author amr ahmed
	 * @category C4S57
	 * @param content
	 *            the content of the comment
	 * @param planID
	 *            the id of the idea that was commented on
	 * 
	 */
	public static void planComment(long planID, String content) {

		validation.required(content).message("Empty Field");
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			Application.showPlan(planID);
		} else {
			Plan plan = Plan.find("byID", planID).first();
			String userName = session.get("username");
			User user = null;
			if (userName != null) {

				user = User.find("byUserName", userName).first();
				if (plan != null) {
					if (plan.planComments.size() != 0) {
						if (plan.planComments.get(plan.planComments.size() - 1).content
								.compareTo(content) != 0) {
							planComment comment = new planComment(0, content,
									user, plan, null);
							comment.save();
							plan.planComments.add(comment);
							plan.save();
							Application.showPlan(planID);
						} else {
							Application.showPlan(planID);
						}
					} else {
						planComment comment = new planComment(0, content, user,
								plan, null);
						comment.save();
						plan.planComments.add(comment);
						plan.save();
						Application.showPlan(planID);
					}
				}
			}
		}
	}

	/**
	 * this method filters search results and gets the list of ideas only to
	 * render
	 * 
	 * @author amr ahmed
	 * @category C4S53
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * @param id
	 *            User id
	 * 
	 */
	public static void filterByIdea(String searchKeyWord) {

		long id;
		String userName = session.get("userName");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			id = user.id;
		} else {
			id = -1;
		}

		List<Idea> ideaByTitleResult = Idea.find("byTitleLike",
				"%" + searchKeyWord + "%").fetch();
		List<Idea> ideaByTagResult = Idea.searchByTag(searchKeyWord);

		render(id, searchKeyWord, ideaByTitleResult, ideaByTagResult);
	}

	/**
	 * this method filters search results and gets the list of organizations
	 * only to render
	 * 
	 * @author amr ahmed
	 * @category C4S53
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * @param id
	 *            User id
	 * 
	 */
	public static void filterByOrg(String searchKeyWord) {

		long id;
		String userName = session.get("userName");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			id = user.id;
		} else {
			id = -1;
		}

		List<Organization> orgByNameResult = Organization.find("byNameLike",
				"%" + searchKeyWord + "%").fetch();

		render(id, searchKeyWord, orgByNameResult);
	}

	/**
	 * this method filters search results and gets the list of topics only to
	 * render
	 * 
	 * @author amr ahmed
	 * @category C4S53
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * @param id
	 *            User id
	 * 
	 */
	public static void filterByTopic(String searchKeyWord) {

		long id;
		String userName = session.get("userName");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			id = user.id;
		} else {
			id = -1;
		}

		List<Topic> topicByNameResult = Topic.find("byNameLike",
				"%" + searchKeyWord + "%").fetch();
		List<Topic> topicByTagResult = Topic.searchByTag(searchKeyWord);

		render(id, searchKeyWord, topicByNameResult, topicByTagResult);

	}

	/**
	 * this method filters search results and gets the list of entities only to
	 * render
	 * 
	 * @author amr ahmed
	 * @category C4S53
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * @param id
	 *            User id
	 * 
	 */
	public static void filterByEntity(String searchKeyWord) {

		long id;
		String userName = session.get("userName");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			id = user.id;
		} else {
			id = -1;
		}

		List<EEntity> entityByNameResult = EEntity.find("byNameLike",
				"%" + searchKeyWord + "%").fetch();
		List<EEntity> entityByKeyResult = EEntity
				.searchByKeyword(searchKeyWord);

		render(id, searchKeyWord, entityByNameResult, entityByKeyResult);
	}

	/**
	 * this method filters search results and gets the list of plans only to
	 * render
	 * 
	 * @author amr ahmed
	 * @category C4S53
	 * @param searchKeyWord
	 *            the phrase or word that the user writes to search
	 * @param id
	 *            User id
	 * 
	 */
	public static void filterByPlan(String searchKeyWord) {

		long id;
		String userName = session.get("userName");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			id = user.id;
		} else {
			id = -1;
		}

		List<Plan> planByTitleResult = Plan.find("byTitleLike",
				"%" + searchKeyWord + "%").fetch();

		render(id, searchKeyWord, planByTitleResult);
	}

	/**
	 * Used to get the list of all ideas within all topics in a certain entity,
	 * and then renders a page where those ideas are displayed to the user in
	 * order to choose from
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 * @param entityId
	 *            The ID of the entity which we want to view all the ideas
	 *            within all its topics
	 */
	public static void showListOfIdeasInEntity(long entityId) {
		String userName = session.get("username");
		if (userName == null)
			notAuthorized();
		else {
			User user = User.find("byUserName", userName).first();
			if (user == null)
				notAuthorized();
			else {
				EEntity currentEntity = EEntity.findById(entityId);
				if (currentEntity == null)
					notFound("Entity");
				else {
					boolean check1 = false;
					boolean check2 = false;
					boolean check3 = false;
					Organization userOrg = currentEntity.organization;
					if (userOrg == null)
						notFound("Organization");
					if (userOrg.organizationLead() == user.id
							|| userOrg.isAsOrganizationLead(user.id))
						check1 = true;
					if (user.isOrganizer(currentEntity.id))
						check2 = true;
					if (user.isSysteAdmin())
						check3 = true;
					if (!check1 && !check2 && !check3)
						notAuthorized();
					else {
						List<Idea> allIdeas = Idea.findAll();
						List<Idea> entityIdeas = new ArrayList<Idea>();
						for (int k = 0; k < allIdeas.size(); k++) {
							if (allIdeas.get(k).topic == null) {
								System.out.println("shit");
								noIdeasInEntity();
							} else {
								if (allIdeas.get(k).topic.entity.id == entityId
										&& allIdeas.get(k).isPromoted)
									entityIdeas.add(allIdeas.get(k));
							}
						}
						if (entityIdeas.isEmpty())
							noIdeasInEntity();
						else
							render(entityId, entityIdeas);
					}
				}
			}
		}
	}

	/**
	 * Used as a controller method to render the page that indicates that there
	 * are no ideas in the entity of the user who wants to create the plan
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 */
	public static void noIdeasInEntity() {
		render();
	}

	/**
	 * Used as a controller method to render the showCreateNewPlan page where
	 * the form of creating a new plan is displayed to the user, and it also
	 * keeps track of what ideas the user chose before in the showListOfAllIdeas
	 * page
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 * @param redirected
	 *            is a boolean flag that checks whether the user visited that
	 *            page before and he was redirected to it for some missing or
	 *            wrong information he inserted, because if so the the user
	 *            won't be taken again to the showListOfAllIdeas page, but the
	 *            page of showCreatNewPlan will be re-displayed, else it means
	 *            that the user did not choose any idea from the list of all
	 *            ideas, so he will go through the showListOfAllIdeas page again
	 */
	public static void showCreateNewPlan(boolean redirected) {
		if (redirected)
			render();
		String[] ids = params.getAll("ids");
		if (ids != null) {
			long[] ideasID = new long[ids.length];
			for (int i = 0; i < ids.length; i++)
				ideasID[i] = Long.parseLong(ids[i]);
			play.cache.Cache.safeSet("ideasID", ideasID, "30mn");
			String entity_id = params.get("entityId");
			if (entity_id == null)
				noIdeasInEntity();
			else {
				long entityId = Long.parseLong(entity_id);
				render(entityId);
			}
		} else {
			validation.addError("", "You didn't choose any idea", "");
			validation.keep();
			String entity_id = params.get("entityId");
			if (entity_id == null)
				noIdeasInEntity();
			else {
				long entityId = Long.parseLong(entity_id);
				showListOfIdeasInEntity(entityId);
			}
		}
	}

	/**
	 * Used to verify that the user inserted valid details of the plan, if that
	 * was verified correctly, then a new plan is created with the details
	 * inserted by the user, and the user is then redirected to the page where
	 * he is asked to insert some actionItems related to his plan, else the page
	 * of showCreateNewPlan is re-displayed
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 * @param title
	 *            is the title of the plan
	 * @param description
	 *            is the description of the plan
	 * @param stDate
	 *            is the start date of the plan
	 * @param endDate
	 *            is the end date of the plan
	 */
	public static void createNewPlan(String title, String description,
			String stDate, String endDate) {
		boolean correctStartDate = true, correctEndDate = true;
		validation.required(title).message(
				"You must enter a title for the plan");
		validation.required(description).message(
				"You must enter a description for the plan");
		validation.minSize(description, 10).message(
				"Too short description for the plan!");
		validation.required(stDate).message(
				"You must enter a start date for the plan");
		validation.required(endDate).message(
				"You must enter an end date for the plan");
		Date start = null, end = null;
		if (stDate.length() > 0) {
			ValidationResult vr = validation
					.match(stDate,
							"^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
			vr.message("The start date format is incorrect make it like yyyy-mm-dd and you better choose from the calender !!!");
			if (vr.ok == true) {
				correctStartDate = true;
				String[] t = stDate.split("-");
				start = parseDate(t[2] + "-" + t[1] + "-" + t[0]);
			}
		}
		if (endDate.length() > 0) {
			ValidationResult vr = validation
					.match(endDate,
							"^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
			vr.message("The end date format is incorrect make it like yyyy-mm-dd and you better choose from the calender !!!");
			if (vr.ok == true) {
				correctEndDate = true;
				String[] t = endDate.split("-");
				end = parseDate(t[2] + "-" + t[1] + "-" + t[0]);
			}
		}
		Date date = new Date();
		if (correctStartDate && start != null && date.compareTo(start) > 0) {
			validation.addError(stDate, "The start date is in the past",
					endDate);
			validation.keep();
		}
		if (correctEndDate && correctStartDate && start != null && end != null
				&& start.compareTo(end) >= 0) {
			validation.addError(stDate,
					"The end date is before the start date", endDate);
			validation.keep();
		}
		if (!(Plan.find("byTitle", title).fetch().isEmpty())) {
			validation.addError("",
					"This Plan Title Already Exists, Choose Another Title", "");
			validation.keep();
		}

		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			showCreateNewPlan(true);
		}
		if (Cache.get("ideasID") == null) {
			validation.addError("", "Cache is cleared or timeout!", "");
			validation.keep();
			String entity_id = params.get("entityId");
			if (entity_id == null)
				noIdeasInEntity();
			else {
				long entityId = Long.parseLong(entity_id);
				showListOfIdeasInEntity(entityId);
			}
		}
		long userId = 1;
		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("byUserName", userName).first();
			userId = user.id;
		}
		User user = User.findById(userId);
		Plan planCreated = new Plan(title, description, 0.0, start, end, user)
				.save();
		long[] ideasID = (long[]) (Cache.get("ideasID"));
		for (int i = 0; i < ideasID.length; i++) {
			Idea idea = Idea.findById(ideasID[i]);
			planCreated.addIdea(idea);
			idea.plans.add(planCreated);
			idea.save();
		}
		planCreated.save();
		long planID = planCreated.getId();
		String userLogMsg = "The user " + user.name
				+ " created a new plan called " + planCreated.title;
		new ActionLog(userLogMsg, user, null).save();
		showPlan(planID);
	}

	public static void showTimeLine(long planId) {
		Plan plan = Plan.findById(planId);
		render(plan);
	}

	/**
	 * loads the time line of the plan page with the action items' start and end
	 * dates as events
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param planId
	 * 
	 * @see app/views/Application/actionItemXML.xml
	 * 
	 */
	public static void actionItemXML(long planId) {
		Plan plan = Plan.findById(planId);
		List<ActionItem> actionItemsList = plan.actionItems;
		render(actionItemsList);
	}

	/**
	 * Used as a controller method to render the page where a certain user can
	 * be assigned to participate in a given action item, and before that get
	 * the list of all users eligible to participate in that action item, and
	 * pass them to the auto complete form
	 * 
	 * @param actionItemId
	 *            The id of the action item to be rendered and passed to the
	 *            HTML page
	 * @story C5S69
	 * @author Sherif Ayad
	 */
	public static void assignUsersToParticipateInActionItem(long actionItemId) {
		ActionItem actionItem = ActionItem.findById(actionItemId);
		if (actionItem == null) {
			notExistingActionItem();
		} else {
			List<User> allUsers = User.findAll();
			List<User> users = new ArrayList<User>();
			if (actionItem.plan.ideas.size() > 0) {
				EEntity planCreatorEntity = actionItem.plan.ideas.get(0).topic.entity;
				for (int i = 0; i < allUsers.size(); i++) {
					List<RoleInEntity> roleInEntity = allUsers.get(i).rolesAndEntities;
					for (int j = 0; j < roleInEntity.size(); j++) {
						if (roleInEntity.get(j).entity.id == planCreatorEntity.id)
							users.add(allUsers.get(i));
					}
				}
			}
			LinkedList<String> names = new LinkedList<String>();
			for (User user : users) {
				names.add(user.userName);
			}
			render(actionItem, names);
		}
	}

	/**
	 * Used as a controller method to render the page which indicates that the
	 * requested action item doesn't exist
	 * 
	 * @story C5S69
	 * @author Sherif Ayad
	 */
	public static void notExistingActionItem() {
		render();
	}

	/**
	 * Insert the given user in the list of users participating in the given
	 * action item, and check whether that user is in the list of allowed users
	 * to participate in that action item or not, if that user is allowed to
	 * participate in the given action item, then insert him in the list of
	 * users of that action item, else show an error indicating that the user is
	 * not allowed
	 * 
	 * @param actionItemId
	 *            The id of the action item that the user will be assigned to
	 * @param userName
	 *            The user name of the user that will participate in the action
	 *            item
	 * @story C5S69
	 * @author Sherif Ayad
	 */
	public static void insertUserInActionItem(long actionItemId, String userName) {
		if (userName != null) {
			User user = User.find("byUserName", userName).first();
			ActionItem currentActionItem = ActionItem.findById(actionItemId);
			if (currentActionItem == null)
				notExistingActionItem();
			if (currentActionItem.plan == null)
				notExistingPlan();
			if (user == null) {
				Validation.addError(userName,
						"You Entered An Invalid User Name", userName);
			} else {
				boolean addOrNot = true;
				for (int i = 0; i < currentActionItem.users.size(); i++) {
					if (currentActionItem.users.get(i).userName
							.equalsIgnoreCase(user.userName))
						addOrNot = false;
				}
				List<User> allUsers = User.findAll();
				List<User> users = new ArrayList<User>();
				if (currentActionItem.plan.ideas.size() > 0) {
					EEntity planCreatorEntity = currentActionItem.plan.ideas
							.get(0).topic.entity;
					for (int i = 0; i < allUsers.size(); i++) {
						List<RoleInEntity> roleInEntity = allUsers.get(i).rolesAndEntities;
						for (int j = 0; j < roleInEntity.size(); j++) {
							if (roleInEntity.get(j).entity.id == planCreatorEntity.id)
								users.add(allUsers.get(i));
						}
					}
				}
				if (addOrNot) {
					boolean flag = false;
					for (int k = 0; k < users.size(); k++) {
						if (users.get(k).userName
								.equalsIgnoreCase(user.userName))
							flag = true;
					}
					if (flag) {
						currentActionItem.users.add(user);
						currentActionItem.save();
						String userLogMsg = "The user "
								+ user.name
								+ " was added to the action item with description "
								+ currentActionItem.description + ". The user "
								+ currentActionItem.plan.creator.userName
								+ " added him";
						new ActionLog(userLogMsg,
								currentActionItem.plan.creator, null).save();
						sendMail(
								"The user \""
										+ currentActionItem.plan.creator.userName
										+ "\" assigned you to participate in an action item for his plan \""
										+ currentActionItem.plan.title
										+ "\".\n\nThe description of that action item is:\n\""
										+ currentActionItem.description + "\".",
								"You were assigned to participate in an action item",
								user);
						List<User> toBeNotified = new ArrayList<User>();
						toBeNotified.add(user);
						new models.Notification(
								"You were assigned to the action item with description: \""
										+ currentActionItem.description + "\"",
								currentActionItem.id, 8,
								currentActionItem.plan.creator, toBeNotified)
								.save();

						assignUsersToParticipateInActionItem(actionItemId);
					} else {
						Validation
								.addError(
										userName,
										"The User You Entered Can Not Participate In That Action Item",
										userName);
					}
				} else {
					Validation
							.addError(
									userName,
									"The User You Entered Already Exists In The List Of Users Participating In That Action Item",
									userName);
				}
			}
			if (validation.hasErrors()) {
				params.flash();
				validation.keep();
				assignUsersToParticipateInActionItem(actionItemId);
			}
		}
	}

	/**
	 * Show the list of all ideas that the creator of the plan can add to the
	 * list of ideas to be implemented by the plan, that method gets all the
	 * ideas within the entity of the creator, and then displays them all,
	 * except the ideas previously implemented by the plan, in order not to
	 * choose the same idea twice
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 * @param planId
	 *            The ID of the plan that the ideas chosen will be associated to
	 */
	public static void showMoreIdeas(long planId) {
		String userName = session.get("username");
		Plan currentPlan = Plan.findById(planId);
		if (userName == null)
			notAuthorized();
		else {
			User user = User.find("byUserName", userName).first();
			if (user == null)
				notAuthorized();
			else {
				if (currentPlan == null)
					notExistingPlan();
				else {
					List<Idea> currentIdeasList = currentPlan.ideas;
					if (currentIdeasList.size() > 0) {
						EEntity currentEntity = currentIdeasList.get(0).topic.entity;
						if (currentEntity == null)
							notFound("Entity");
						else {
							boolean check1 = false;
							boolean check2 = false;
							List<RoleInOrganization> userRoleInOrg = user.rolesAndOrganization;
							List<RoleInEntity> userRoleInEntity = user.rolesAndEntities;
							for (int i = 0; i < userRoleInOrg.size(); i++) {
								if (userRoleInOrg.get(i).role.description
										.equalsIgnoreCase("organizationlead")
										&& userRoleInOrg.get(i).organization.id == currentEntity.organization.id)
									check1 = true;
							}
							for (int j = 0; j < userRoleInEntity.size(); j++) {
								if (userRoleInEntity.get(j).role.description
										.equalsIgnoreCase("organizer")
										&& userRoleInEntity.get(j).entity.id == currentEntity.id)
									check2 = true;
							}
							if (!check1 && !check2)
								notAuthorized();
							else {
								List<Idea> allIdeas = Idea.findAll();
								List<Idea> entityIdeas = new ArrayList<Idea>();
								for (int k = 0; k < allIdeas.size(); k++) {
									if (allIdeas.get(k).topic == null)
										noIdeasInEntity();
									else {
										if (allIdeas.get(k).topic.entity.id == currentEntity.id
												&& allIdeas.get(k).isPromoted)
											entityIdeas.add(allIdeas.get(k));
									}
								}
								List<Idea> currentIdeas = currentPlan.ideas;
								for (int i = 0; i < currentIdeas.size(); i++) {
									for (int j = 0; j < entityIdeas.size(); j++) {
										if (entityIdeas.get(j).id == currentIdeas
												.get(i).id)
											entityIdeas.remove(j);
									}
								}
								if (entityIdeas.isEmpty())
									noIdeasInEntity();
								else
									render(entityIdeas, planId);
							}
						}
					} else
						noIdeasInEntity();
				}
			}
		}
	}

	/**
	 * Get the ideas checked by the user, and add those ideas to the list of all
	 * ideas implemented by the plan, the method also checks that the user chose
	 * any ideas or not
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 * @param planId
	 */
	public static void addMoreIdeas(long planId) {
		String[] ids = params.getAll("ids");
		if (ids != null) {
			long[] ideasID = new long[ids.length];
			for (int i = 0; i < ids.length; i++)
				ideasID[i] = Long.parseLong(ids[i]);
			Plan currentPlan = Plan.findById(planId);
			if (currentPlan == null)
				notExistingPlan();
			else {
				for (int k = 0; k < ideasID.length; k++) {
					Idea ideaToAdd = Idea.findById(ideasID[k]);
					currentPlan.addIdea(ideaToAdd);
				}
				currentPlan.save();
				showPlan(planId);
			}
		} else {
			validation.addError("", "You didn't choose any idea", "");
			validation.keep();
			showMoreIdeas(planId);
		}
	}

	/**
	 * Used to restore an idea which was deleted for the list of all ideas
	 * associated to a plan
	 * 
	 * @param planId
	 *            The ID of the plan to which the idea will be restored
	 * @param ideaId
	 *            The ID of the idea that will be restored
	 * @author Sherif Ayad
	 * @story C5S65
	 */
	public static void restoreIdea(long planId, long ideaId) {
		Plan plan = Plan.findById(planId);
		plan.restoreIdea(ideaId);
		plan.save();
		renderText("LOL");
	}

	/**
	 * Used to remove an idea from the list of all ideas associated to a plan
	 * 
	 * @param planId
	 *            The ID of the plan from which an idea will be removed
	 * @param ideaId
	 *            The ID of the idea to be removed
	 * @author Sherif Ayad
	 * @story C5S65
	 */
	public static void removeIdea(long planId, long ideaId) {
		Plan plan = Plan.findById(planId);
		plan.removeIdea(ideaId);
		plan.save();
		renderText("LOL");
	}

	/**
	 * Used to accept the request of a user to join an action item, whenever the
	 * creator of the plan clicks the accept button he is redirected to this
	 * method which allows him to add the user to the list of users
	 * participating in that action item, and send him an e-mail and a
	 * notification indicating that
	 * 
	 * @param itemId
	 *            The ID of the action item to which a user will be added
	 * @param requesterId
	 *            The ID of the user who requested to join the actionItem
	 * @param planCreatorId
	 *            The ID of the creator of the plan and of course the action
	 *            Item
	 * @param requestId
	 *            The ID of the request which the user sent to the plan creator
	 * @author Sherif Ayad
	 * @story C5S71
	 */
	public static void acceptRequestToJoinAnActionItem(long itemId,
			long requesterId, long planCreatorId, long requestId) {
		ActionItem actionItem = ActionItem.findById(itemId);
		if (actionItem == null)
			notExistingActionItem();
		else {
			User requester = User.findById(requesterId);
			if (requester == null)
				notLoggedIn();
			else {
				User reciever = User.findById(planCreatorId);
				if (reciever == null)
					notLoggedIn();
				else {
					Request request = Request.findById(requestId);
					if (request != null)
						actionItem.requestsToJoin.remove(request);
					actionItem.save();
					actionItem.plan.save();
					insertUserInActionItem(actionItem.id, requester.userName);
				}
			}
		}
	}

	/**
	 * Used to reject a user's request to join an action item, and then send the
	 * user a notfication and a mail indicating that
	 * 
	 * @param itemId
	 *            The ID of the item to which the user was supposed to be added
	 * @param requesterId
	 *            The ID of the user who requested to join the actionItem
	 * @param planCreatorId
	 *            The ID of the creator of the plan and of course the action
	 *            item
	 * @param requestId
	 *            The ID of the request which the user sent to the plan creator
	 * @author Sherif Ayad
	 * @story C5S71
	 */
	public static void rejectRequestToJoinAnActionItem(long itemId,
			long requesterId, long planCreatorId, long requestId) {
		ActionItem actionItem = ActionItem.findById(itemId);
		if (actionItem == null)
			notExistingActionItem();
		else {
			User requester = User.findById(requesterId);
			if (requester == null)
				notLoggedIn();
			else {
				User reciever = User.findById(planCreatorId);
				if (reciever == null)
					notLoggedIn();
				else {
					Request request = Request.findById(requestId);
					if (request != null)
						actionItem.requestsToJoin.remove(request);
					actionItem.save();
					actionItem.plan.save();
					sendMail(
							"The user \""
									+ actionItem.plan.creator.userName
									+ "\" rejected your request to participate in an action item for his plan \""
									+ actionItem.plan.title
									+ "\".\n\nThe description of that action item is:\n\""
									+ actionItem.description + "\".",
							"Your request to participate in an action item was rejected",
							requester);
					List<User> toBeNotified = new ArrayList<User>();
					toBeNotified.add(requester);
					new models.Notification(
							"You were rejected to participate in the action item with description: \""
									+ actionItem.description + "\"",
							actionItem.id, 8, actionItem.plan.creator,
							toBeNotified).save();

					assignUsersToParticipateInActionItem(actionItem.id);
				}
			}
		}
	}

	// Ayad's method

	/**
	 * Update the status of the action item
	 * 
	 * @param itemId
	 *            The ID of the action item to be updated
	 * @param progress
	 *            The variable that represents the updated status
	 * @author Sherif Ayad
	 */

	public static void updateActionItemStatus(long itemId, String progress) {
		ActionItem actionItem = ActionItem.findById(itemId);
		if (actionItem == null) {
			notExistingActionItem();
		} else {
			double prog = 0.0;
			try {
				prog = Double.parseDouble(progress);
			} catch (NumberFormatException e) {
				validation.addError("", "Please Enter A Valid Number", "");
			}

			if (prog < 0 || prog > 100)
				validation.addError("",
						"Please enter a number between 0 and 100", progress);
			double theStatus;
			if (validation.hasErrors()) {
				params.flash();
				validation.keep();
				showPlan(actionItem.plan.id);
			}
			theStatus = Double.parseDouble(progress);
			actionItem.status = theStatus;
			actionItem.save();
			showPlan(actionItem.plan.id);
		}
	}

	/**
	 * the method takes a rating and the user who chose this rating and the
	 * rated idea and update the rating if the idea was already rated by this
	 * user or add the new rating if it wasn't rated by this user be4
	 * 
	 * @param idea
	 *            the idea that will be rated
	 * @param user
	 *            the rating user
	 * @param newUserRating
	 *            the new rating chosen by the user.
	 * @return boolean, true if it's new Rating. False if it's changing rating.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static boolean addOrUpdateRating(Idea idea, User user,
			int newUserRating) {
		boolean isAuthorized = false;
		if (idea.topic.entity.organization.isPrivate()
				|| idea.topic.entity.organization.isSecret()) {
			if (idea.topic.entity.organization.isMember(user.id)) {
				isAuthorized = true;
			} else {
				isAuthorized = false;
			}
		} else {
			isAuthorized = true;
		}

		if (!isAuthorized) {
			return false;
		}
		user = User.findById(user.id);
		idea = Idea.findById(idea.id);
		List<IdeaRating> ideaRatings = user.ideasRatings;
		for (IdeaRating ideaRating : ideaRatings) {
			if (ideaRating.idea.id == idea.id) { // if true then it's nt new
				double newIdeaRating = calculateChangedRating(ideaRating,
						newUserRating); // rating

				ideaRating.updateRating(newUserRating, newIdeaRating);// the
																		// user's
																		// rating
				return false;
			}
		}
		// the rating is new.
		new IdeaRating(idea, user, newUserRating).save();
		double rating = calculateNewRating(idea, newUserRating);
		idea.updateRating(rating);// the whole value
		return true;
	}

	/**
	 * the method adds the new rating to the idea Rating.
	 * 
	 * @param idea
	 *            the rated idea.
	 * @param newRating
	 *            the new rating will be added
	 * @return double, the new rating for the idea.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static double calculateNewRating(Idea idea, int newRating) {
		int n = idea.ideaRatings.size();
		return (((n - 1) * idea.rating) + newRating) / ((n - 1) + 1);
	}

	/**
	 * the method calculates the new rating for the idea after changing one of
	 * its previous ratings
	 * 
	 * @param ideaRating
	 *            the ideaRating object that contains the rated idea, the old
	 *            rating, and the rating user.
	 * @param newRating
	 *            the new rating chose by the user
	 * @return double, the new calculated rating for the idea.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static double calculateChangedRating(IdeaRating ideaRating,
			int newRating) {
		int n = ideaRating.idea.ideaRatings.size();
		double rating = ideaRating.idea.rating;
		int oldRating = ideaRating.rating;
		return ((n * rating) - oldRating + newRating) / n;
	}

	/**
	 * it's the method called from the View of the IdeaRating UI.
	 * 
	 * @param rating
	 *            the rating chosen by the user
	 * @param ideaId
	 *            the id of the rated idea
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static void rateIdea(int rating, long ideaId) {
		String userName = session.get("username");
		notFoundIfNull(userName);

		validation.range(rating, 1, 5);
		validation.range(ideaId, 1, Idea.count());
		if (validation.hasErrors()) {
			notFound("Error with id of the idea or the rating range");
		}

		User user = User.find("byUserName", userName).first();
		Idea idea = Idea.findById(ideaId);
		if (idea == null || user == null) {
			notFound("Error the idea or the user is not found");
		}

		boolean isAuthorized = false;
		if (idea.topic.entity.organization.isPrivate()
				|| idea.topic.entity.organization.isSecret()) {
			if (idea.topic.entity.organization.isMember(user.id)) {
				isAuthorized = true;
			} else {
				isAuthorized = false;
			}
		} else {
			isAuthorized = true;
		}
		if (isAuthorized) {
			addOrUpdateRating(idea, user, rating); // no data yet.
			renderText((int) idea.rating);
		} else {
			forbidden();
		}
	}

	/**
	 * gives some organizers lead's privilages.It does part of the job where
	 * it's responsible for listing the organizers of a certain organization by
	 * an order from organization lead.So given the organization id and user id
	 * (who should be this organization lead or previously given lead
	 * privileges). it renders an html file (giveOrganizerRole) which prints a
	 * list of all organizer allowing the user to choose and then calls the
	 * method giveOrganizerLeadPrivilages to continue the task.
	 * 
	 * @author Omar Darwish
	 * @param orgID
	 *            the id of the organization this method will act on as
	 *            specified
	 * @see a list of all organizers in given organization who are not given
	 *      lead privilages.
	 */
	public static void giveOrganizerRole(long orgID) {
		int logged = 0;
		boolean flag = false;
		Organization organization = Organization.findById(orgID);
		User user = null;
		String username = session.get("username");
		if (username != null)
			user = User.find("byUserName", username).first();
		if (username != null && user != null && organization != null) {
			long userID = user.id;
			flag = organization.getOrganizationLead().id == userID
					|| organization.isAsOrganizationLead(userID);
		}
		if (!flag) {
			render(logged);
		} else {
			List<User> temp = organization.getOrganizersList();
			LinkedList<User> organizers = new LinkedList<User>();
			for (User item : temp) {
				if (!(organization.isAsOrganizationLead(item.id) || organization
						.getOrganizationLead().id == item.id))
					organizers.add(item);
			}
			if (organizers.size() == 0) {
				logged = 1;
				render(logged, organization);
			} else {
				logged = 2;
				render(logged, organizers, organization);
			}
		}
	}

	/**
	 * gives some organizers the lead privileges in a specific organization It
	 * continues the work of giveOrganizerRole method.It does so by Assigning to
	 * the organizer the role AsOrganizationLead.And at last it send an email to
	 * these organizers to notify them with such change.
	 * 
	 * @author Omar Darwish
	 * @param orgID
	 *            the id of the organization.
	 * @see Just succes page to clarify action success.
	 */
	public static void giveOrganizerLeadPrivilages(long orgID) {
		String[] organizers = params.getAll("organizerID");
		validation.required(organizers).message(
				"You must choose at least one organizer");
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			giveOrganizerRole(orgID);
		} else {
			long[] organizerID = new long[organizers.length];
			for (int i = 0; i < organizerID.length; i++) {
				organizerID[i] = Long.parseLong(organizers[i]);
			}
			Role temp = Role.find("byDescription", "AsOrganizationLead")
					.first();
			Organization organization = Organization.findById(orgID);
			List<RoleInOrganization> current = organization.rolesAndUsers;
			for (int i = 0; i < organizerID.length; i++) {
				for (RoleInOrganization item : current) {
					if (item.user.id == organizerID[i]
							&& item.role.description
									.equalsIgnoreCase("IdeaDeveloper")) {
						item.role = temp;
						item.save();
					}
				}
			}
			List<User> users = new LinkedList<User>();
			for (int i = 0; i < organizerID.length; i++) {
				users.add((User) User.findById(organizerID[i]));
			}
			for (int i = 0; i < organizerID.length; i++) {
				String message = "The organization lead of the organization "
						+ organization.name
						+ " has given you all his privilages in this "
						+ "organization";
				User user = User.findById(organizerID[i]);
				sendMail(message, "Given Lead privilages", user);
			}
			render(organization, users, orgID);
		}
	}

	/**
	 * gets a list of all organizers in a specific organization who were
	 * previously given lead privileges and renders an html page that views this
	 * list for an organization lead to choose one or more of them to remove
	 * those privileges from.Only this organization lead would be allowed to do
	 * this action.It does part of the action of removing lead privileges from
	 * some organizers previously given those.
	 * 
	 * @author Omar Darwish.
	 * @param orgID
	 *            the organization id which its lead want to remove lead
	 *            privileges from some of those previously given.
	 * @see a list of all organizers in this organization previously given lead
	 *      privileges.
	 * @story C1-S3ReverseAction.
	 */
	public static void givenLeadPrivilagesList(long orgID) {
		int logged = 0;
		boolean flag = false;
		Organization organization = Organization.findById(orgID);
		User user = null;
		String username = session.get("username");
		if (username != null)
			user = User.find("byUserName", username).first();
		if (username != null && user != null && organization != null) {
			long userID = user.id;
			flag = organization.getOrganizationLead().id == userID;
		}
		if (!flag) {
			render(logged);
		} else {
			LinkedList<User> givenPrivileges = organization
					.getAsOrganizationLeadList();
			if (givenPrivileges.size() == 0) {
				logged = 1;
				render(logged, organization);
			} else {
				logged = 2;
				render(logged, givenPrivileges, organization);
			}
		}
	}

	/**
	 * removes lead privileges from some organizers in specific organization by
	 * an order from this organization lead.It renders a page notifying action
	 * success and sends a mail to organizers action performed on for
	 * notification.
	 * 
	 * @author Omar Darwish.
	 * @param orgID
	 *            the organization id where this action previously clarified
	 *            happens.
	 * @see a succes page clarifying the succes of this action.
	 * @story C1-S3ReverseAction
	 * 
	 */
	public static void removeLeadPrivilages(long orgID) {
		String[] organizers = params.getAll("organizerID");
		validation.required(organizers).message(
				"You must choose at least one organizer");
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			givenLeadPrivilagesList(orgID);
		} else {
			long[] organizerID = new long[organizers.length];
			for (int i = 0; i < organizerID.length; i++) {
				organizerID[i] = Long.parseLong(organizers[i]);
			}
			Role temp = Role.find("byDescription", "IdeaDeveloper").first();
			Organization organization = Organization.findById(orgID);
			List<RoleInOrganization> current = organization.rolesAndUsers;
			for (int i = 0; i < organizerID.length; i++) {
				for (RoleInOrganization item : current) {
					if (item.user.id == organizerID[i]
							&& item.role.description
									.equalsIgnoreCase("AsOrganizationLead")) {
						item.role = temp;
						item.save();
					}
				}
			}
			List<User> users = new LinkedList<User>();
			for (int i = 0; i < organizerID.length; i++) {
				users.add((User) User.findById(organizerID[i]));
			}
			for (int i = 0; i < organizerID.length; i++) {
				String message = "The organization lead of the organization "
						+ organization.name
						+ " has removed from you all his privileges";
				User user = User.findById(organizerID[i]);
				sendMail(message, "Removed Lead privileges", user);
			}
			render(organization, users, orgID);
		}
	}

	/**
	 * A method that given a user id, an organization id and a search keyword it
	 * renders a list of entities, topic and ideas that lie in the organization
	 * and match the keyword.It first calls method Application.getResults which
	 * get all results that match search word and then filter those that are not
	 * in the organization
	 * 
	 * @author Islam Al-Aarag
	 * @param userID
	 *            the id of the user that is trying to search within the
	 *            organization or -1 if he is not logged in
	 * @param orgID
	 *            the id of the organization the user is trying to search within
	 * @param searchWord
	 *            the keyword that the user want to the results to be related
	 *            too
	 */
	public static void searchOrganization(long orgID, String searchWord) {
		List<Object> allResults = getResults(searchWord);
		List<Idea> oldIdeaByTitleResult = (List<Idea>) allResults.get(0);
		List<Idea> ideaByTitleResult = new ArrayList<Idea>();
		for (Idea idea : oldIdeaByTitleResult)
			if (idea.topic.entity.organization.id == orgID)
				ideaByTitleResult.add(idea);
		List<Idea> oldIdeaByTagResult = (List<Idea>) allResults.get(1);
		List<Idea> ideaByTagResult = new ArrayList<Idea>();
		for (Idea idea : oldIdeaByTagResult)
			if (idea.topic.entity.organization.id == orgID)
				ideaByTagResult.add(idea);
		List<Organization> orgByNameResult = new ArrayList<Organization>();
		List<EEntity> oldEntityByNameResult = (List<EEntity>) allResults.get(3);
		List<EEntity> entityByNameResult = new ArrayList<EEntity>();
		for (EEntity entity : oldEntityByNameResult)
			if (entity.organization.id == orgID)
				entityByNameResult.add(entity);
		List<EEntity> oldEntityByKeyResult = (List<EEntity>) allResults.get(4);
		List<EEntity> entityByKeyResult = new ArrayList<EEntity>();
		for (EEntity entity : oldEntityByKeyResult)
			if (entity.organization.id == orgID)
				entityByKeyResult.add(entity);
		List<Plan> oldPlanByTitleResult = (List<Plan>) allResults.get(5);
		List<Plan> planByTitleResult = new ArrayList<Plan>();
		for (Plan plan : oldPlanByTitleResult)
			if (plan.ideas.get(0).topic.entity.organization.id == orgID)
				planByTitleResult.add(plan);
		List<Topic> oldTopicByNameResult = (List<Topic>) allResults.get(6);
		List<Topic> topicByNameResult = new ArrayList<Topic>();
		for (Topic topic : oldTopicByNameResult)
			if (topic.entity.organization.id == orgID)
				topicByNameResult.add(topic);
		List<Topic> oldTopicByTagResult = (List<Topic>) allResults.get(7);
		List<Topic> topicByTagResult = new ArrayList<Topic>();
		for (Topic topic : oldTopicByTagResult)
			if (topic.entity.organization.id == orgID)
				topicByTagResult.add(topic);

		List<Object> modifiedResultSet = new LinkedList<Object>();
		modifiedResultSet.add(ideaByTitleResult);
		modifiedResultSet.add(ideaByTagResult);
		modifiedResultSet.add(orgByNameResult);
		modifiedResultSet.add(entityByNameResult);
		modifiedResultSet.add(entityByKeyResult);
		modifiedResultSet.add(planByTitleResult);
		modifiedResultSet.add(topicByNameResult);
		modifiedResultSet.add(topicByTagResult);
		long id = -1;
		String userName = session.get("username");
		User user = null;
		if (userName != null) {
			user = User.find("byUserName", userName).first();
			if (user != null) {
				id = user.id;
			}
		}
		LinkedList<Object> hashObj = new LinkedList<Object>();
		hashObj.add(id);
		hashObj.add(searchWord);
		String key = hashObj.hashCode() + "";
		play.cache.Cache.safeSet(key, modifiedResultSet, "30mn");
		render("Application/searchResults.html", ideaByTitleResult,
				ideaByTagResult, orgByNameResult, entityByNameResult,
				entityByKeyResult, planByTitleResult, topicByNameResult,
				topicByTagResult);
	}

	/**
	 * this methods renders the sendInv html page for sending the invitation
	 */
	public static void sendInv() {
		render();
	}

	/**
	 * A controller method that sends an email invitation to an unregistered
	 * user, it checks that the sent inviation is sent to an unregistered user.
	 * 
	 * @param msg
	 *            this is the content of the inivitaion which is actually the
	 *            link of the registeration page.
	 * @param subject
	 *            the subject of the email inviation t hat will be sent
	 * @param toEmail
	 *            the email of the unregistered user
	 * @param name
	 *            the name of the sender
	 * @return returns true of the email invitation is sent sucessfully
	 *         otherwise returns false
	 */
	public static boolean sendInvitation(String msg, @Required String subject,
			@Required @Email String toEmail, String name) {
		String userName = session.get("username");
		boolean flag = false;
		if (validation.email(toEmail).ok) {
			if (userName != null) {
				for (int i = 0; i < User.getListOfOrderedUsers().size(); i++) {
					if (toEmail
							.equals(User.getListOfOrderedUsers().get(i).email)) {
						registeredBefore();
					} else {

						flag = true;
					}
				}
			} else {
				notLoggedIn();
			}

		} else {
			invalidMail();
		}
		if (flag) {
			return sendMail(msg, subject, toEmail, name);

		} else {
			return false;
		}
	}

	/**
	 * A method taht renders a page when the email is invalid
	 * 
	 * @author Alaa Tarek
	 */

	public static void invalidMail() {
		render();

	}

	/**
	 * A method that renders a page when the user is not logged in
	 * 
	 * @author Alaa Tarek
	 */
	public static void notLoggedIn() {
		render();

	}

	/**
	 * A method that renders a page when the user is register before on the
	 * system.
	 * 
	 * @author Alaa Tarek
	 */

	public static void registeredBefore() {
		render();
	}

	/**
	 * A method that showa that an invitation is sucessfully sent
	 * 
	 * @author Alaa Tarek
	 * @param msg
	 *            the content of email
	 * @param subject
	 *            the subject of the email
	 * @param toEmail
	 *            the email address to be sent to
	 * @param name
	 *            the name of the reciever
	 */
	public static void showInvSent(@Required String msg,
			@Required String subject, @Required String toEmail, String name) {
		User u1 = new User("u1", "male", "u1", "limpbizkit", new Date(),
				"u1hamdymassoud@gmail.com", "cairo").save();
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			sendInv();
		} else {

			sendInvitation(msg, subject, toEmail, name);
		}
		render();
	}

	/**
	 * the method takes a String representing a date with format dd-mm-yyyy and
	 * parse the string and return a corresponding Date Object. Only Numbers are
	 * allowed.
	 * 
	 * @param dateRepresentation
	 *            the String representing the desired date to be parsed
	 * @return Date, the date resulted from parsing the string or null if the
	 *         String representing the date is in wrong format.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public static Date parseDate(String dateRepresentation) {
		if (dateRepresentation == null || dateRepresentation.equals("")) {
			return null;
		}
		String[] dateValues = dateRepresentation.split("-");
		if (dateValues.length != 3) {
			return null;
		}
		Calendar calendar = Calendar.getInstance();
		try {
			calendar.set(Calendar.DATE, Integer.parseInt(dateValues[0]));
			calendar.set(Calendar.MONTH, Integer.parseInt(dateValues[1]) - 1);
			calendar.set(Calendar.YEAR, Integer.parseInt(dateValues[2]));
		} catch (NumberFormatException e) {
			return null;
		} catch (ArrayIndexOutOfBoundsException e) {
			return null;
		}
		return calendar.getTime();
	}

	/**
	 * a method that renders a list of all organizers in an organization
	 * 
	 * @author Alaa Tarek
	 * 
	 * @param orgID
	 *            this is the id of the organization to get the list of its
	 *            organizers
	 * 
	 */
	public static void listOfOrganizers(long orgID) {
		Organization org = Organization.findById(orgID);
		List<User> organizers = org.getOrganizersList();
		render(organizers, orgID);
	}

	/**
	 * A method that gets a list of all organizers in an organization
	 * 
	 * @author Alaa Tarek
	 * 
	 * @param orgID
	 *            the id of the organization
	 * @return a list of organizers in a specific organization
	 */
	public static List<User> listOfOrganizers2(long orgID) {
		Organization org = Organization.findById(orgID);
		List<User> organizers = org.getOrganizersList();
		return organizers;
	}

	/**
	 * a method that gets a list of entities organized by a certain organizer
	 * 
	 * @author Alaa Tarek
	 * @param userId
	 *            this is the id of the organizer that will be used to get the
	 *            entities he is assigned to
	 **/
	public static void getListofEntitiesOfOrganizer(long userId, long orgID) {
		User user = User.findById(userId);
		if (user != null) {
			User u = User.findById(userId);
			Organization organization = Organization.findById(orgID);

			List<EEntity> entities = new ArrayList<EEntity>();
			List<EEntity> entitiesOfOrg = new ArrayList<EEntity>();
			for (int i = 0; i < u.rolesAndEntities.size(); i++) {
				entities.add(u.rolesAndEntities.get(i).entity);
			}
			List<EEntity> organizerEntities = organization
					.getEntitiesOfOrganizer(userId);
			for (int i = 0; i < entities.size(); i++) {
				for (int j = 0; j < organizerEntities.size(); j++) {
					System.out.println("LIST SIZE " + organizerEntities.size());
					EEntity entity = organizerEntities.get(j);
					if (entities.get(i).id == entity.id) {
						entitiesOfOrg.add(entities.get(i));

					}
				}
			}

			render(userId, entitiesOfOrg, orgID);
		} else {
			pleaseChoose1(orgID);
		}
	}

	/**
	 * A method tha rrenders a page to tell the user that he must choose
	 * something from the shown list
	 * 
	 * @author Alaa Tarek
	 * @param orgID
	 *            the id of the organization the user is in.
	 */
	public static void pleaseChoose1(long orgID) {
		render(orgID);

	}

	/**
	 * a method that gets the list of allowed topics for a certain user
	 * 
	 * @author Alaa Tarek
	 * @param userId
	 *            the id of the user that will be used get the list of topics in
	 *            a certain entity for this specific organizer.
	 * @param entityId
	 *            the id of the entity
	 */
	public static void getListOfTopics(long userId, long entityId, long orgID) {
		EEntity entity = EEntity.findById(entityId);
		List<Topic> topics = new ArrayList<Topic>();
		if (entity != null) {
			EEntity e = EEntity.findById(entityId);
			User u = User.findById(userId);
			topics = e.getTopics();

		} else {
			pleaseChoose2(userId, orgID);
		}

		render(userId, topics, entityId, orgID);
	}

	/**
	 * A method tha rrenders a page to tell the user that he must choose
	 * something from the shown list
	 * 
	 * @author Alaa Tarek
	 * @param orgID
	 *            the id of the organization the user is in.
	 */

	public static void pleaseChoose2(long userId, long orgID) {
		render(userId, orgID);

	}

	/**
	 * This is a method that restricts a certain organizer from a certain topics
	 * in a certain entity
	 * 
	 * @author Alaa Tarek
	 * @param userId
	 *            this is the id of the organizer that will be restricted
	 */

	public static void restrict(long userId, long entityId, long orgID) {
		boolean flag = false;
		String[] strIDs = params.getAll("topics");
		if (strIDs != null) {
			long[] topicsIDs = new long[strIDs.length];
			for (int i = 0; i < topicsIDs.length; i++) {
				topicsIDs[i] = Long.parseLong(strIDs[i]);
			}

			List<Topic> restrictedTopics = new ArrayList<Topic>();
			User u = User.findById(userId);
			for (int j = 0; j < topicsIDs.length; j++) {
				for (int i = 0; i < u.allowedTopics.size(); i++) {
					Topic t = Topic.findById(topicsIDs[j]);
					if (u.allowedTopics.get(i) == t) {
						u.allowedTopics.get(i).delete();
						restrictedTopics.add(t);
					} else {
						flag = true;
					}
				}
			}

			sendMail("You are restricted to the following topics"
					+ restrictedTopics, "restrictions", u.email, u.name);
			render(flag, orgID);
		} else {
			pleaseChoose3(userId, entityId, orgID);
		}

		render(flag, orgID);

	}

	/**
	 * A method that renders a page to warn the user that he must choose
	 * something from a list displayed for him
	 * 
	 * @author Alaa Tarek
	 * @param userId
	 * @param entityId
	 * @param orgID
	 */
	private static void pleaseChoose3(long userId, long entityId, long orgID) {
		render(userId, entityId, orgID);

	}

	/**
	 * just method to redirect to some page telling that the user is not
	 * authorized for some action
	 */
	public static void notAuthorized() {
		render();
	}

	/**
	 * method to show the error message if user tries to show non-existing plan
	 * through typing wrong url
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @see app/views/Application/noeExistingPlan.html
	 */
	public static void notExistingPlan() {
		render();
	}

	public static void autoComplete() {
		List<User> users = User.findAll();
		LinkedList<String> names = new LinkedList<String>();
		for (User user : users) {
			names.add(user.userName);
		}
		render(names);
	}

	/**
	 * renders the edit page of the plan with the current values of the plan
	 * attributes shown in editable fields that can be used to edit the plan
	 * infomration
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param planId
	 *            the id of the plan to be edited
	 * @see app/views/Application/editPlan.html
	 */
	public static void editPlan(long planId) {
		Plan plan = Plan.findById(planId);
		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("byUserName", userName).first();
			if (user == null
					|| (user.id != plan.creator.id && !user.isSysteAdmin())) {
				notAuthorized();
			}
		} else {
			notAuthorized();
		}
		render(plan);
	}

	/**
	 * used to allow any user to send his/her feedback to the application admin
	 * and to report encountered bugs
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param msg
	 *            the message that the user wants to send to the admin
	 * @param name
	 *            the name of the user wants to send his feedback
	 */
	public static void sendFeedback(String msg, String name) {
		validation.required(msg);
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			index();
		}
		if (name == null || name.equals("jiot"))
			name = "anonymous";
		boolean sent = sendMail(msg, "SuperSoft FeedBack",
				"kamokim2@gmail.com", name);
		if (sent) {
			renderText("success");
		} else
			renderText("failure");
	}

	/**
	 * removes action item from a plan through calling a Plan model method that
	 * actually removes the action item, it renders a text message "success" if
	 * the item was correclty removed else it renders "failure" and this message
	 * is used in informing the user about the result of his removal action
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param planId
	 *            the id of the plan that have the action item to be removed
	 * @param actionItemId
	 *            the id of the action item to be reomved
	 */
	public static void removeActionItem(long planId, long actionItemId) {
		Plan plan = Plan.findById(planId);
		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("byUserName", userName).first();
			if (user == null
					|| (user.id != plan.creator.id && !user.isSysteAdmin())) {
				notAuthorized();
			}
		} else {
			notAuthorized();
		}
		plan.removeActionItem(actionItemId);
		plan.save();
		renderText("success");
	}

	/**
	 * restores action item to a plan through calling a Plan model method that
	 * actually resotres the action item, it renders a text message "success" if
	 * the item was correclty removed else it renders "failure" and this message
	 * is used in informing the user about the result of his restore action
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param planId
	 *            the id of the plan that have the action item to be restored
	 * @param actionItemId
	 *            the id of the action item to be restores
	 */
	public static void restoreActionItem(long planId, long actionItemId) {
		Plan plan = Plan.findById(planId);
		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("byUserName", userName).first();
			if (user == null
					|| (user.id != plan.creator.id && !user.isSysteAdmin())) {
				notAuthorized();
			}
		} else {
			notAuthorized();
		}
		plan.restoreActionItem(actionItemId);
		plan.save();
		renderText("success");
	}

	/**
	 * A method that gets a list of organizers that can be assgined to a certain
	 * entities inside a certain organization
	 * 
	 * @author Alaa Tarek
	 * @param entities
	 *            list of entities
	 * @param orgId
	 *            the id of the organization
	 * @return list of organizers that can be assigned to the list of entities
	 */

	public static List<User> canBeAssigned(List<EEntity> entities, long orgId) {
		boolean flag = false;
		List<User> allUsers = listOfOrganizers2(orgId);
		List<User> toBeAssigned = new ArrayList<User>();
		for (int i = 0; i < allUsers.size(); i++) {
			for (int j = 0; j < allUsers.get(i).rolesAndEntities.size(); j++) {
				EEntity entity = allUsers.get(i).rolesAndEntities.get(j).entity;
				for (int k = 0; k < entities.size(); k++) {
					if (entities.get(k).name.equals(entity.name)) {
						flag = true;

					}
				}
			}
			if (!flag) {
				toBeAssigned.add(allUsers.get(i));
			}

		}
		return toBeAssigned;

	}

	/**
	 * This a method that assigns a certain user to certain entities.
	 * 
	 * @author Alaa Tarek
	 * @param userId
	 *            this the user id of the user that will be assign to the
	 *            entities
	 * 
	 */

	public static void assignToEntity(long userId, long[] entitiesIDs,
			long orgId) {

		Organization org = Organization.findById(orgId);

		User user = User.findById(userId);
		if (user == null) {
			pleaseChoose4(orgId, 0, 0);
		}
		List<EEntity> entities = new ArrayList<EEntity>();
		String entitiesString = "";
		boolean flag = false;
		for (int i = 0; i < entitiesIDs.length; i++) {
			EEntity entity = EEntity.findById(entitiesIDs[i]);
			entities.add(entity);

		}

		Role role = Role.findOrCreate("Organizer");
		for (int i1 = 0; i1 < entities.size(); i1++) {
			EEntity entity = entities.get(i1);

			entitiesString = entitiesString + entity.name + '\n' + '&';
			RoleInEntity roleInEnt = new RoleInEntity(entity, user, role)
					.save();
			user.rolesAndEntities.add(roleInEnt);
			flag = true;
		}
		entitiesString = entitiesString.substring(0,
				entitiesString.length() - 2);
		render(flag, entitiesString, userId, orgId);

	}

	public static void pleaseChoose4(long orgId, int i2, int v1) {
		render(orgId, i2, v1);
	}

	/**
	 * A method that return the list of all entities inside a specific
	 * organization
	 * 
	 * @author Alaa Tarek
	 * @param orgId
	 *            is the id of the organization which is used to get the
	 *            organization entities.
	 */

	public static void viewEntitiesOfOrg(long orgId, int view) {

		Organization org = Organization.findById(orgId);
		List<EEntity> orgEntities = org.entities;
		String[] strIDs = params.getAll("orgEntities");
		String entitiesString = "";
		List<EEntity> toBeChecked = new ArrayList<EEntity>();
		if (view == 1) {
			if (strIDs == null) {
				pleaseChoose5(orgId, 0, 0);
			}
			long[] entitiesIDs = new long[strIDs.length];

			if (strIDs != null) {
				for (int i = 0; i < entitiesIDs.length; i++) {
					entitiesIDs[i] = Long.parseLong(strIDs[i]);
				}
			}
			for (int j = 0; j < entitiesIDs.length; j++) {
				EEntity entity = EEntity.findById(entitiesIDs[j]);
				entitiesString = entitiesString + entity.name + '\n' + '&';
				toBeChecked.add(entity);

			}
			List<User> canBeAssigned = canBeAssigned(toBeChecked, orgId);
			entitiesString = entitiesString.substring(0,
					entitiesString.length() - 2);

			render(orgEntities, orgId, canBeAssigned, view, entitiesIDs,
					entitiesString);

		} else {
			render(orgEntities, orgId, view);
		}

	}

	public static void pleaseChoose5(Long orgId, int i, int v) {
		render(orgId, i, v);

	}

	/**
	 * A method that return the list of all entities inside a specific
	 * organization
	 * 
	 * @author Alaa Tarek
	 * @param orgId
	 *            is the id of the organization which is used to get the
	 *            organization entities.
	 */

	public static void viewEntitiesOfOrg2(long orgId, int view) {
		Organization org = Organization.findById(orgId);
		List<EEntity> orgEntities = org.entities;
		String[] strIDs = params.getAll("orgEntities");
		List<EEntity> toBeChecked = new ArrayList<EEntity>();
		String entitiesString = "";
		if (view == 1) {
			if (strIDs == null) {
				pleaseChoose5(orgId, 0, 1);
			}
			long[] entitiesIDs = new long[strIDs.length];
			if (strIDs != null) {
				for (int i = 0; i < entitiesIDs.length; i++) {
					entitiesIDs[i] = Long.parseLong(strIDs[i]);
				}
			}
			for (int j = 0; j < entitiesIDs.length; j++) {
				EEntity entity = EEntity.findById(entitiesIDs[j]);
				entitiesString = entitiesString + entity.name + '\n' + '&';
				toBeChecked.add(entity);

			}
			List<User> canBeRemove = canBeRemoved(toBeChecked, orgId);
			entitiesString = entitiesString.substring(0,
					entitiesString.length() - 2);
			render(orgEntities, orgId, canBeRemove, view, entitiesIDs,
					entitiesString);

		} else {

			render(orgEntities, orgId, view);
		}
	}

	/**
	 * A mthod that checks that a list of user can be removed from certain
	 * entities.
	 * 
	 * @author Alaa Tarek
	 * @param toBeChecked
	 *            the list that will be checked
	 * @param orgId
	 *            the id of the organization
	 * @return list of organizers that can be removed from certain entitities
	 */

	public static List<User> canBeRemoved(List<EEntity> toBeChecked, long orgId) {
		Organization org = Organization.findById(orgId);
		List<User> canBeRemoved = new ArrayList<User>();
		List<User> allUsers = listOfOrganizers2(orgId);
		boolean flag = false;
		for (int i = 0; i < toBeChecked.size(); i++) {
			for (int j = 0; j < toBeChecked.get(i).rolesAndUsers.size(); j++) {
				canBeRemoved.add(toBeChecked.get(i).rolesAndUsers.get(j).user);
			}
		}

		return canBeRemoved;

	}

	/**
	 * A method that removes a certain organizer from certain entities.
	 * 
	 * @author Alaa Tarek
	 * 
	 * @param userId
	 *            is the id of the organizer that will be used to remove him/her
	 *            from the entities.
	 */
	public static void removeFromEntity(long userId, long[] entitiesIDs,
			long orgId) {
		Organization org = Organization.findById(orgId);
		User user = User.findById(userId);
		if (user == null) {
			pleaseChoose4(orgId, 0, 1);
		}
		List<EEntity> entities = new ArrayList<EEntity>();
		String entitiesString = "";
		boolean test = false;
		for (int i = 0; i < entitiesIDs.length; i++) {
			EEntity entity = EEntity.findById(entitiesIDs[i]);
			entities.add(entity);

		}

		for (int i = 0; i < entitiesIDs.length; i++) {
			EEntity entity = EEntity.findById(entitiesIDs[i]);
			entitiesString = entitiesString + entity.name + '\n' + '&';
			for (int j = 0; j < entity.rolesAndUsers.size(); j++) {
				if (entity.rolesAndUsers.get(j).user.id == userId) {
					entity.rolesAndUsers.get(j).cascadeDelete();
					test = true;

				}

			}

			for (int k = 0; k < user.rolesAndEntities.size(); k++) {
				if (user.rolesAndEntities.get(k).entity.name
						.equals(entity.name)) {
					user.rolesAndEntities.get(k).cascadeDelete();
				}

			}
		}
		entitiesString = entitiesString.substring(0,
				entitiesString.length() - 2);
		render(test, entitiesString, userId, orgId);

	}

	/**
	 * A method that sends an invitation to a user in the system to be an
	 * orgaizer to a list of entities.
	 * 
	 * @author Alaa Tarek
	 * @param userId
	 *            is the id of the user that inivitation will be sent to.
	 * @param entities
	 *            is the list of entitis that will be assgined to the user.
	 */

	public static void sendOrganizerInvitation(long userId, String entities) {
		String subject = "Invitation to be an organizer";
		String toEmail;
		User user = User.findById(userId);
		toEmail = user.email;
		String name = user.name;
		String message;
		message = "Dear"
				+ user.name
				+ " you are invited to be the organizer of the following entities";
		int i = 0;
		if (entities.charAt(i) != '&') {
			message += entities.charAt(i);
			i++;
		}
		if (entities.charAt(i) == '+') {
			message += '\n';
			i++;

		}

		sendMail(message, subject, toEmail, name);
	}

	/**
	 * A method that renders a list of organizers in a specific organization
	 * 
	 * @author Alaa Tarek
	 * @param orgId
	 *            the id of the specific organization
	 * 
	 */

	public static void organizersOfOrg(long orgId) {

		Organization org = Organization.findById(orgId);
		List<User> organizers = org.getOrganizersList();
		render(organizers);

	}

	/**
	 * A method taht checks taht a certain user is blocked from a certain
	 * organization
	 * 
	 * @author Alaa Tarek
	 * @param userId
	 *            the id of the user to be check that he is blocked
	 * @param orgId
	 *            the organization id of the organization.
	 * @return
	 */
	public static boolean isBlocked(long userId, long orgId) {
		Organization org = Organization.findById(orgId);
		User user = User.findById(userId);
		boolean flag = false;
		if (org.blockedusers != null) {
			for (int i = 0; i < org.blockedusers.size(); i++) {
				if (org.blockedusers.get(i).name.equals(user.name)) {
					flag = true;
				}

			}
		}
		return flag;

	}

	/**
	 * A method that renders a list of oragnizer and the organization id
	 * 
	 * @author Alaa Tarek
	 * @param orgId
	 *            organization id
	 */

	/**
	 * 
	 * @param userId
	 * @param orgId
	 */

	public static void block(long orgId) {
		List<User> organizers = listOfOrganizers2(orgId);
		for (int i = 0; i < organizers.size(); i++) {
			if (isBlocked(organizers.get(i).id, orgId)) {
				organizers.remove(i);
			}
		}
		render(organizers, orgId);
	}

	/**
	 * A method that renders a list of oragnizer and the organization id
	 * 
	 * @author Alaa Tarek
	 * @param orgId
	 *            organization id
	 */

	public static void unblock(long orgId) {
		List<User> organizers = listOfOrganizers2(orgId);
		render(organizers, orgId);
	}

	/**
	 * A method that blocks a user from a specfic organization.
	 * 
	 * @author Alaa Tarek
	 * @param userId
	 *            the is of the user to be blocked.
	 * @param orgId
	 *            the id of the organization which the user will be blocked
	 *            from.
	 */

	public static void blockUser(long userId, long orgId, String reason) {
		boolean flag = false;
		Organization org = Organization.findById(orgId);
		User user = User.findById(userId);
		User lead = User.findById(org.organizationLead());
		if (!isBlocked(userId, orgId)) {
			org.blockedusers.add(user);
			user.blockedOrganizations.add(org);
			List<User> organizers = org.getOrganizersList();
			Notification notify = new Notification("The user:  " + user.name
					+ "  is block for the following reasons:" + reason, userId,
					6, lead, organizers).save();

			flag = true;
		}
		render(flag, orgId);
	}

	/**
	 * a method that unblockes a user from a cetain organization
	 * 
	 * @author Alaa Tarek
	 * @param userId
	 *            the id of the user to be unblocked
	 * @param orgId
	 *            the id of the organization that the user will be unblocked
	 *            from.
	 */

	public static void unblockUser(long userId, long orgId, String reason) {
		boolean flag = false;
		Organization org = Organization.findById(orgId);
		User user = User.findById(userId);
		User lead = User.findById(org.organizationLead());
		if (isBlocked(userId, orgId)) {
			org.blockedusers.remove(user);
			user.blockedOrganizations.remove(org);
			List<User> organizers = org.getOrganizersList();
			Notification notify = new Notification("The user:" + user.name
					+ "for the following reasons:" + reason, userId, 6, lead,
					organizers).save();
			flag = true;
		}
		render(flag, orgId);

	}

	/**
	 * 
	 * updates the basic information of the plan i.e. the static infomration
	 * that rarely changes during plan execution like the description and
	 * title..etc , then redirects the user ,if every thing was ok with the
	 * validations of the input, to the updated plan page where he/she can see
	 * the modifications that has been done to the specified plan
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param planId
	 *            the id of the plan to be updated
	 * @param title
	 *            the update title if this specific plan(specified by the id)
	 * @param newDescription
	 *            the updated description of this specific plan
	 * @param newStartDate
	 *            the updated start date of execution for this plan
	 * @param newEndDate
	 *            the updated end date of execution for this plan
	 * 
	 * @see app/views/Application/showPlan.html
	 */

	public static void updatePlan(long planId, String title,
			String newDescription, String newStartDate, String newEndDate) {
		validation.clear();
		Plan plan = Plan.findById(planId);
		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("byUserName", userName).first();
			if (user == null
					|| (user.id != plan.creator.id && !user.isSysteAdmin())) {
				notAuthorized();
			}
		} else {
			notAuthorized();
		}
		boolean correctStartDate = false, correctEndDate = false;
		Date start = null, end = null;
		Plan plan2 = Plan.find("byTitle", title).first();
		validation.required(newDescription).message(
				"You must enter plan Description");
		validation.required(title).message("You must enter title for the plan");
		validation.match(title, "^\\w+$").message(
				"only alpha numeric characters allowed for the title");
		validation.minSize(title, 3).message(
				"The title can not be less than 3 letters");
		validation.required(newEndDate).message(
				"You must enter an end date for the plan");
		validation.minSize(newDescription, 10).message(
				"The plan description can not be less than 10 letters");
		if (newStartDate.length() > 0) {
			ValidationResult vr = validation
					.match(newStartDate,
							"^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
			vr.message("The start date fomate is not correct make it like yyyy-mm-dd and you better choose from the calender !!!");
			if (vr.ok == true) {
				correctStartDate = true;
				String[] splitted = newStartDate.split("-");
				start = parseDate(splitted[2] + "-" + splitted[1] + "-"
						+ splitted[0]);
			}
		}
		if (plan2 != null && !plan.title.equals(title)) {
			validation.addError(newStartDate,
					"The Plan title is already there choose another title",
					newEndDate);
			validation.keep();
		}
		if (newEndDate.length() > 0) {
			ValidationResult vr = validation
					.match(newEndDate,
							"^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))$");
			vr.message("The end date fomate is not correct make it like yyyy-mm-dd and you better choose from the calender !!!");
			if (vr.ok == true) {
				correctEndDate = true;
				String[] splitted = newEndDate.split("-");
				end = parseDate(splitted[2] + "-" + splitted[1] + "-"
						+ splitted[0]);
			}
		}
		Date date = new Date();
		if (correctStartDate && start != null && date.compareTo(start) > 0) {
			validation.addError(newStartDate, "The start date is in the past",
					newEndDate);
			validation.keep();
		}
		if (correctEndDate && correctStartDate && start != null && end != null
				&& start.compareTo(end) > 0) {
			validation.addError(newStartDate,
					"The end date is before the start date", newEndDate);
			validation.keep();
		}
		if (validation.hasErrors()) {
			params.flash();
			validation.keep();
			if (plan.ideasToBeRemoved != null) {
				plan.ideasToBeRemoved.clear();
				plan.save();
			}
			if (plan.toBeRemoved != null) {
				plan.toBeRemoved.clear();
				plan.save();
			}
			editPlan(planId);
		} else {
			if (plan.toBeRemoved != null) {
				for (Long id : plan.toBeRemoved) {
					ActionItem aI = ActionItem.findById(id);
					if (aI != null)
						aI.cascadeDelete();
				}
				plan.toBeRemoved = new ArrayList<Long>();
			}
			if (plan.ideasToBeRemoved != null) {
				if (plan.ideasToBeRemoved.size() == plan.ideas.size()) {
					validation
							.addError(
									"",
									"You removed all the ideas of the plan, the plan can't implement NO ideas",
									"");
					validation.keep();
					plan.ideasToBeRemoved.clear();
					plan.save();
					editPlan(planId);
				} else {
					for (Long id : plan.ideasToBeRemoved) {
						Idea idea = Idea.findById(id);
						if (idea != null)
							plan.ideas.remove(idea);
					}
				}
			}
			plan.title = title;
			plan.description = newDescription;
			String[] splitted = newStartDate.split("-");
			plan.startDate = parseDate(splitted[2] + "-" + splitted[1] + "-"
					+ splitted[0]);
			splitted = newEndDate.split("-");
			plan.endDate = parseDate(splitted[2] + "-" + splitted[1] + "-"
					+ splitted[0]);
			plan.save();
			User user = User.find("byUserName", userName).first();
			String blockedUserIdMsg = "User name " + user.name
					+ " updated Plan " + plan.title;
			new ActionLog(blockedUserIdMsg, user, null).save();
			showPlan(plan.id);
		}
	}

	/**
	 * the method checks if the user can promote idea or not
	 * 
	 * @author Abdullah abd-alhady
	 * @param ideaId
	 *            the id of the idea.
	 * @return it return true if the user is organiztionlead or orgnizer
	 * 
	 */
	public static boolean isAllowToPromote(long ideaId) {

		User user = User.getUserInfo(session.get("username"));
		if (user == null) {
			render("Application/notLoggedIn.html");
		}
		Idea idea = Idea.findById(ideaId);
		List<User> orginzers = idea.topic.entity.getOrganizers();
		return idea.topic.entity.organization.getOrganizationLead()
				.equals(user)
				|| orginzers.contains(user)
				|| user.isSysteAdmin();
	}

	/**
	 * the method promote idea to be ready to enter plan
	 * 
	 * @story C3S38
	 * @author Abdullah abdalhady
	 * @param ideaId
	 *            the id of the idea you want to promote
	 */
	public static void promoteIdea(long ideaId) {
		Idea idea = Idea.findById(ideaId);
		User user = User.getUserInfo(session.get("username"));
		if (user == null) {
			render("Application/notLoggedIn.html");
		}
		String Msg = "User name " + user.name + " promoted the idea"
				+ idea.title;
		new ActionLog(Msg, user, null).save();
		if (idea != null) {
			idea.isPromoted = true;
			idea.save();
			Browse.viewIdea(ideaId);
		}
	}

	/**
	 * the method unpromote idea
	 * 
	 * @story C3S38
	 * @author Abdullah abdalhady
	 * @param ideaId
	 *            the id of the idea you want to unpromote
	 */
	public static void unPromoteIdea(long ideaId) {
		Idea idea = Idea.findById(ideaId);
		User user = User.getUserInfo(session.get("username"));
		if (user == null) {
			render("Application/notLoggedIn.html");
		}
		String Msg = "User name " + user.name + " unpromoted the idea"
				+ idea.title;
		new ActionLog(Msg, user, null).save();

		if (idea != null) {
			idea.isPromoted = false;
			idea.save();
			Browse.viewIdea(ideaId);
		}

	}

	/**
	 * Renders the view responsible for adding users to entities as organizers.
	 * Organization leads and organizers of a given organization are allowed to
	 * perform the action. If the current user is not an organization lead or
	 * organizer within the organization, no entities will be listed.
	 * 
	 * @param orgID
	 *            The organization, of which the according entities will be
	 *            listed.
	 * @param message
	 *            The optional success message after submitting.
	 * @param error
	 *            The optional error message after submitting.
	 * 
	 * @author Johannes Schmidt (schmjoha@googlemail.com)
	 * @story C1S6
	 */
	public static void addOrganizerToEntity(long orgID, String message,
			String error) {
		String sessionUsername = session.get("username");
		User sessionUser = User.getUserInfo(sessionUsername);

		List<EEntity> entities = new ArrayList<EEntity>();
		List<User> users = User.find("order by username asc").fetch();

		// Get entities for organization lead
		for (RoleInOrganization roleInOrganization : sessionUser.rolesAndOrganization) {
			if (roleInOrganization.organization.id == orgID
					&& roleInOrganization.role.description
							.equalsIgnoreCase("OrganizationLead")) {
				for (EEntity entity : roleInOrganization.organization.entities) {
					if (!entities.contains(entity))
						entities.add(entity);
				}
			}
		}

		// Get list of entities for organizers
		for (RoleInEntity roleInEntity : sessionUser.rolesAndEntities) {
			if (roleInEntity.entity.organization.id == orgID
					&& roleInEntity.role.description
							.equalsIgnoreCase("Organizer")) {
				if (!entities.contains(roleInEntity))
					entities.add(roleInEntity.entity);
			}
		}
		render(entities, users, message, error);

	}

	/**
	 * Adds a given user as organizer to a given entity. If the user is not a
	 * member of the entity's organization, he will become a member.
	 * 
	 * @param entityID
	 *            The entity id the given user will be added to as organizer.
	 * @param username
	 *            The user who will become an organizer in the given entity.
	 * 
	 * @author Johannes Schmidt (schmjoha@googlemail.com)
	 * @story C1S6
	 */
	public static void submitOrganizerToEntity(int entityID, String username) {
		EEntity entity = EEntity.getEntityById(entityID);
		User user = User.getUserInfo(username);

		String sessionUsername = session.get("username");
		User sessionUser = User.getUserInfo(sessionUsername);

		Role organizer = Role.findOrCreate("Organizer");
		Role ideaDeveloper = Role.findOrCreate("IdeaDeveloper");

		if (!user.isOrganizer(entity.id)) {
			RoleInEntity roleInEntity = new RoleInEntity(entity, user,
					organizer);
			RoleInOrganization roleInOrganization = new RoleInOrganization(
					entity.organization, user, ideaDeveloper);

			// If user is not a member of the organization, he will become a
			// member first
			if (!entity.organization.isMember(user.id)) {
				// Create log record if user becomes member of the given
				// organization
				entity.organization.addRoleAndUser(roleInOrganization);
				String logMessage = "User name " + user.userName
						+ " became member of the organization "
						+ entity.organization.name;
				new ActionLog(logMessage, sessionUser, null).save();
			}
			entity.addRoleAndUser(roleInEntity);

			// Create log record if user successfully added a user as organizer
			// to an entity
			String logMessage = "User name " + user.userName
					+ " became member of the entity " + entity.name
					+ " within the " + "organization "
					+ entity.organization.name;
			new ActionLog(logMessage, sessionUser, null).save();

			addOrganizerToEntity(entity.organization.id,
					"Successfully added user to entity.", null);
		} else
			addOrganizerToEntity(entity.organization.id, null,
					"The chosen user is already organizer of the given entity.");
	}

	/**
	 * Given a date it returns a string representing how long ago was this date
	 * (e.g: 3 hours ago, 2 minutes ago,...etc)
	 * 
	 * @param dateToMap
	 *            the date you want to know its age
	 * @return String the age of this date with regard to today's date and time
	 */
	public static String dateMap(Date dateToMap) {
		if (dateToMap == null) {
			return "N/A";
		}
		Date currentDate = new Date();
		int yearDif = currentDate.getYear() - dateToMap.getYear();
		int monthDif = currentDate.getMonth() - dateToMap.getMonth();
		int dayDif = currentDate.getDay() - dateToMap.getDay();
		int hourDif = currentDate.getHours() - dateToMap.getHours();
		int minuteDif = currentDate.getMinutes() - dateToMap.getMinutes();
		int secondDif = currentDate.getSeconds() - dateToMap.getSeconds();
		if (yearDif > 1 || (yearDif == 1 && monthDif >= 0))
			return yearDif + " year(s) ago";
		else
			monthDif += yearDif * 12;
		if (monthDif > 1 || (monthDif == 1 && dayDif >= 0))
			return monthDif + " month(s) ago";
		else
			dayDif += monthDif * 30;
		if (dayDif > 1 || (dayDif == 1 && hourDif >= 0))
			return dayDif + " day(s) ago";
		else
			hourDif += dayDif * 24;
		if (hourDif > 1 || (hourDif == 1 && minuteDif >= 0))
			return hourDif + " hour(s) ago";
		else
			minuteDif += hourDif * 60;
		if (minuteDif > 1 || (minuteDif == 1 && secondDif >= 0))
			return minuteDif + " minute(s) ago";
		else
			secondDif += minuteDif * 60;
		return secondDif + " second(s) ago";
	}

	/**
	 * A method that gets the password of a user provided the email of the user.
	 * This method is used in case the user forgets his password. The user is
	 * prompt to enter his e-mail. The email is passed to this method that fins
	 * the user and his/her password.
	 * 
	 * @author Mostafa Ali
	 * 
	 * @param email
	 *            The email of the user that forgot the password.
	 * 
	 * @return void
	 * */

	public static void getForgottenPassword(String email) {
		User user = User.find("byEmail", email).first();
		if (user != null) {
			String userPassword = user.password;
			Application.sendMail("Your password is: \n" + userPassword,
					"Your Forgotten Password", user);
			renderText("success");
		} else {
			renderText("failure");
		}
	}

	/**
	 * method that removes a user's old profile picture and uploads a new one
	 * 
	 * @author omar fouda
	 * @param picture
	 *            , the new picture to be uploaded
	 * @param userId
	 *            , the id of the user changing the picture
	 */

	public static void uploadPicture(Picture picture, String userId) {
		int temp = Integer.parseInt(userId);
		long userIdLong = (long) temp;

		User user = User.findById(userIdLong);
		user.userPicture = null;
		user.save();

		picture.save();
		user.userPicture = picture;
		user.save();
		picture.user = user;
		picture.save();
		// Users.viewUserProfile(user.userName);
		Users.showWall();

	}

	/**
	 * Method that displays the profile picture of a certain user
	 * 
	 * @author omar fouda
	 * 
	 * @param userId
	 *            , id of the user whose picture we want
	 */
	public static void getPicture(long userId) {
		User user = User.findById(userId);
		Picture picture = user.userPicture;
		response.setContentTypeIfNotSet(picture.image.type());
		renderBinary(picture.image.get());
	}

}
